You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by na...@apache.org on 2015/08/05 16:39:56 UTC

jclouds-labs git commit: JCLOUDS-971: add etcd provider. For this initial commit we are only addressing the miscellaneous and statistics API's.

Repository: jclouds-labs
Updated Branches:
  refs/heads/master 9c19ee0c8 -> 9cd3cfa50


JCLOUDS-971: add etcd provider. For this initial commit we are only addressing the miscellaneous and statistics API's.


Project: http://git-wip-us.apache.org/repos/asf/jclouds-labs/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds-labs/commit/9cd3cfa5
Tree: http://git-wip-us.apache.org/repos/asf/jclouds-labs/tree/9cd3cfa5
Diff: http://git-wip-us.apache.org/repos/asf/jclouds-labs/diff/9cd3cfa5

Branch: refs/heads/master
Commit: 9cd3cfa50bdc7621c1398413c8aae29b797958cd
Parents: 9c19ee0
Author: Christopher Dancy <da...@pega.com>
Authored: Mon Jul 27 13:30:57 2015 -0400
Committer: Ignasi Barrera <na...@apache.org>
Committed: Wed Aug 5 15:48:19 2015 +0200

----------------------------------------------------------------------
 etcd/pom.xml                                    | 123 ++++++++++++++
 .../src/main/java/org/jclouds/etcd/EtcdApi.java |  33 ++++
 .../java/org/jclouds/etcd/EtcdApiMetadata.java  |  88 ++++++++++
 .../jclouds/etcd/config/EtcdHttpApiModule.java  |  35 ++++
 .../etcd/domain/miscellaneous/Version.java      |  38 +++++
 .../jclouds/etcd/domain/statistics/Counts.java  |  38 +++++
 .../etcd/domain/statistics/Follower.java        |  38 +++++
 .../jclouds/etcd/domain/statistics/Latency.java |  45 ++++++
 .../jclouds/etcd/domain/statistics/Leader.java  |  41 +++++
 .../etcd/domain/statistics/LeaderInfo.java      |  40 +++++
 .../jclouds/etcd/domain/statistics/Self.java    |  55 +++++++
 .../jclouds/etcd/domain/statistics/Store.java   |  68 ++++++++
 .../jclouds/etcd/features/MiscellaneousApi.java |  49 ++++++
 .../jclouds/etcd/features/StatisticsApi.java    |  48 ++++++
 .../org/jclouds/etcd/BaseEtcdApiLiveTest.java   |  46 ++++++
 .../org/jclouds/etcd/EtcdApiMetadataTest.java   |  50 ++++++
 .../etcd/features/MiscellaneousApiLiveTest.java |  53 ++++++
 .../etcd/features/MiscellaneousApiMockTest.java |  88 ++++++++++
 .../etcd/features/StatisticsApiLiveTest.java    |  44 +++++
 .../etcd/features/StatisticsApiMockTest.java    |  91 +++++++++++
 .../jclouds/etcd/internal/BaseEtcdMockTest.java | 102 ++++++++++++
 etcd/src/test/resources/health.json             |   1 +
 etcd/src/test/resources/leader.json             |  31 ++++
 etcd/src/test/resources/metrics.txt             | 160 +++++++++++++++++++
 etcd/src/test/resources/self.json               |  15 ++
 etcd/src/test/resources/store.json              |  16 ++
 etcd/src/test/resources/version.json            |   4 +
 pom.xml                                         |   1 +
 28 files changed, 1441 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/pom.xml
----------------------------------------------------------------------
diff --git a/etcd/pom.xml b/etcd/pom.xml
new file mode 100644
index 0000000..f83e72c
--- /dev/null
+++ b/etcd/pom.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.jclouds.labs</groupId>
+        <artifactId>jclouds-labs</artifactId>
+        <version>2.0.0-SNAPSHOT</version>
+    </parent>
+  
+    <!-- TODO: when out of labs, switch to org.jclouds.api -->
+    <artifactId>etcd</artifactId>
+    <name>jclouds etcd api</name>
+    <description>jclouds components to access an implementation of etcd</description>
+    <packaging>bundle</packaging>
+
+    <properties>
+        <test.etcd.endpoint>http://127.0.0.1:2379</test.etcd.endpoint>
+        <test.etcd.identity>FIXME</test.etcd.identity>
+        <test.etcd.credential>FIXME</test.etcd.credential>
+        <test.etcd.api-version>v2</test.etcd.api-version>
+        <jclouds.osgi.export>org.jclouds.etcd*;version="${project.version}"</jclouds.osgi.export>
+        <jclouds.osgi.import>
+            org.jclouds*;version="${jclouds.version}",
+            *
+        </jclouds.osgi.import>
+    </properties>
+  
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.jclouds</groupId>
+            <artifactId>jclouds-core</artifactId>
+            <version>${jclouds.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.auto.service</groupId>
+            <artifactId>auto-service</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.google.auto.value</groupId>
+            <artifactId>auto-value</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <!-- Test dependencies -->
+        <dependency>
+            <groupId>org.apache.jclouds</groupId>
+            <artifactId>jclouds-core</artifactId>
+            <version>${jclouds.version}</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.squareup.okhttp</groupId>
+            <artifactId>mockwebserver</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.jclouds.driver</groupId>
+            <artifactId>jclouds-slf4j</artifactId>
+            <version>${jclouds.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+  
+    <profiles>
+        <profile>
+            <id>live</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>integration</id>
+                                <phase>integration-test</phase>
+                                <goals>
+                                    <goal>test</goal>
+                                </goals>
+                                <configuration>
+                                    <systemPropertyVariables>
+                                        <test.etcd.endpoint>${test.etcd.endpoint}</test.etcd.endpoint>
+                                        <test.etcd.identity>${test.etcd.identity}</test.etcd.identity>
+                                        <test.etcd.credential>${test.etcd.credential}</test.etcd.credential>
+                                        <test.etcd.api-version>${test.etcd.api-version}</test.etcd.api-version>
+                                    </systemPropertyVariables>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/main/java/org/jclouds/etcd/EtcdApi.java
----------------------------------------------------------------------
diff --git a/etcd/src/main/java/org/jclouds/etcd/EtcdApi.java b/etcd/src/main/java/org/jclouds/etcd/EtcdApi.java
new file mode 100644
index 0000000..dc3e0cb
--- /dev/null
+++ b/etcd/src/main/java/org/jclouds/etcd/EtcdApi.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd;
+
+import java.io.Closeable;
+
+import org.jclouds.etcd.features.StatisticsApi;
+import org.jclouds.etcd.features.MiscellaneousApi;
+import org.jclouds.rest.annotations.Delegate;
+
+public interface EtcdApi extends Closeable {
+
+   @Delegate
+   StatisticsApi statisticsApi();
+
+   @Delegate
+   MiscellaneousApi miscellaneousApi();
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/main/java/org/jclouds/etcd/EtcdApiMetadata.java
----------------------------------------------------------------------
diff --git a/etcd/src/main/java/org/jclouds/etcd/EtcdApiMetadata.java b/etcd/src/main/java/org/jclouds/etcd/EtcdApiMetadata.java
new file mode 100644
index 0000000..acec91a
--- /dev/null
+++ b/etcd/src/main/java/org/jclouds/etcd/EtcdApiMetadata.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.apis.ApiMetadata;
+import org.jclouds.etcd.config.EtcdHttpApiModule;
+import org.jclouds.rest.internal.BaseHttpApiMetadata;
+
+import com.google.auto.service.AutoService;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+
+@AutoService(ApiMetadata.class)
+public class EtcdApiMetadata extends BaseHttpApiMetadata<EtcdApi> {
+
+   public static final String API_VERSION = "v2";
+   public static final String BUILD_VERSION = "2.1.1";
+
+   @Override
+   public Builder toBuilder() {
+      return new Builder().fromApiMetadata(this);
+   }
+
+   public EtcdApiMetadata() {
+      this(new Builder());
+   }
+
+   protected EtcdApiMetadata(Builder builder) {
+      super(builder);
+   }
+
+   public static Properties defaultProperties() {
+      Properties properties = BaseHttpApiMetadata.defaultProperties();
+      return properties;
+   }
+
+   public static class Builder extends BaseHttpApiMetadata.Builder<EtcdApi, Builder> {
+
+      protected Builder() {
+         super(EtcdApi.class);
+         id("etcd").
+         name("Etcd API").
+         identityName("Optional Username").
+         credentialName("Optional Password").
+         defaultIdentity("N/A").
+         defaultCredential("N/A").
+         documentation(URI.create("https://github.com/coreos/etcd/blob/master/Documentation/api.md")).
+         version(API_VERSION).
+         buildVersion(BUILD_VERSION).
+         defaultEndpoint("http://127.0.0.1:2379").
+         defaultProperties(EtcdApiMetadata.defaultProperties()).
+         defaultModules(ImmutableSet.<Class<? extends Module>> of(EtcdHttpApiModule.class));
+      }
+
+      @Override
+      public EtcdApiMetadata build() {
+         return new EtcdApiMetadata(this);
+      }
+
+      @Override
+      protected Builder self() {
+         return this;
+      }
+
+      @Override
+      public Builder fromApiMetadata(ApiMetadata in) {
+         return this;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/main/java/org/jclouds/etcd/config/EtcdHttpApiModule.java
----------------------------------------------------------------------
diff --git a/etcd/src/main/java/org/jclouds/etcd/config/EtcdHttpApiModule.java b/etcd/src/main/java/org/jclouds/etcd/config/EtcdHttpApiModule.java
new file mode 100644
index 0000000..db492b4
--- /dev/null
+++ b/etcd/src/main/java/org/jclouds/etcd/config/EtcdHttpApiModule.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd.config;
+
+import org.jclouds.etcd.EtcdApi;
+import org.jclouds.rest.ConfiguresHttpApi;
+import org.jclouds.rest.config.HttpApiModule;
+
+@ConfiguresHttpApi
+public class EtcdHttpApiModule extends HttpApiModule<EtcdApi> {
+
+   @Override
+   protected void bindErrorHandlers() {
+
+   }
+
+   protected void configure() {
+      super.configure();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/main/java/org/jclouds/etcd/domain/miscellaneous/Version.java
----------------------------------------------------------------------
diff --git a/etcd/src/main/java/org/jclouds/etcd/domain/miscellaneous/Version.java b/etcd/src/main/java/org/jclouds/etcd/domain/miscellaneous/Version.java
new file mode 100644
index 0000000..60d05ed
--- /dev/null
+++ b/etcd/src/main/java/org/jclouds/etcd/domain/miscellaneous/Version.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd.domain.miscellaneous;
+
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+public abstract class Version {
+
+   public abstract String etcdServer();
+
+   public abstract String etcdCluster();
+
+   Version() {
+   }
+
+   @SerializedNames({ "etcdserver", "etcdcluster" })
+   public static Version create(String etcdserver, String etcdcluster) {
+      return new AutoValue_Version(etcdserver, etcdcluster);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Counts.java
----------------------------------------------------------------------
diff --git a/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Counts.java b/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Counts.java
new file mode 100644
index 0000000..e1d4fda
--- /dev/null
+++ b/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Counts.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd.domain.statistics;
+
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+public abstract class Counts {
+
+   public abstract int fail();
+
+   public abstract int success();
+
+   Counts() {
+   }
+
+   @SerializedNames({ "fail", "success" })
+   public static Counts create(int fail, int success) {
+      return new AutoValue_Counts(fail, success);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Follower.java
----------------------------------------------------------------------
diff --git a/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Follower.java b/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Follower.java
new file mode 100644
index 0000000..a7204f2
--- /dev/null
+++ b/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Follower.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd.domain.statistics;
+
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+public abstract class Follower {
+
+   public abstract Counts counts();
+
+   public abstract Latency latency();
+
+   Follower() {
+   }
+
+   @SerializedNames({ "counts", "latency" })
+   public static Follower create(Counts counts, Latency latency) {
+      return new AutoValue_Follower(counts, latency);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Latency.java
----------------------------------------------------------------------
diff --git a/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Latency.java b/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Latency.java
new file mode 100644
index 0000000..20797b0
--- /dev/null
+++ b/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Latency.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd.domain.statistics;
+
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+public abstract class Latency {
+
+   public abstract double average();
+
+   public abstract double current();
+
+   public abstract double maximum();
+
+   public abstract double minimum();
+
+   public abstract double standardDeviation();
+
+   Latency() {
+   }
+
+   @SerializedNames({ "average", "current", "maximum", "minimum", "standardDeviation" })
+   public static Latency create(double average, double current, double maximum, double minimum,
+         double standardDeviation) {
+      return new AutoValue_Latency(average, current, maximum, minimum, standardDeviation);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Leader.java
----------------------------------------------------------------------
diff --git a/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Leader.java b/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Leader.java
new file mode 100644
index 0000000..b537c53
--- /dev/null
+++ b/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Leader.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd.domain.statistics;
+
+import java.util.Map;
+
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableMap;
+
+@AutoValue
+public abstract class Leader {
+
+   public abstract String leader();
+
+   public abstract Map<String, Follower> followers();
+
+   Leader() {
+   }
+
+   @SerializedNames({ "leader", "followers" })
+   public static Leader create(String leader, Map<String, Follower> followers) {
+      return new AutoValue_Leader(leader, ImmutableMap.copyOf(followers));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/main/java/org/jclouds/etcd/domain/statistics/LeaderInfo.java
----------------------------------------------------------------------
diff --git a/etcd/src/main/java/org/jclouds/etcd/domain/statistics/LeaderInfo.java b/etcd/src/main/java/org/jclouds/etcd/domain/statistics/LeaderInfo.java
new file mode 100644
index 0000000..c220463
--- /dev/null
+++ b/etcd/src/main/java/org/jclouds/etcd/domain/statistics/LeaderInfo.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd.domain.statistics;
+
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+public abstract class LeaderInfo {
+
+   public abstract String leader();
+
+   public abstract String startTime();
+
+   public abstract String uptime();
+
+   LeaderInfo() {
+   }
+
+   @SerializedNames({ "leader", "startTime", "uptime" })
+   public static LeaderInfo create(String leader, String startTime, String uptime) {
+      return new AutoValue_LeaderInfo(leader, startTime, uptime);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Self.java
----------------------------------------------------------------------
diff --git a/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Self.java b/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Self.java
new file mode 100644
index 0000000..bfe9bc2
--- /dev/null
+++ b/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Self.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd.domain.statistics;
+
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+public abstract class Self {
+
+   public abstract String id();
+
+   public abstract LeaderInfo leaderInfo();
+
+   public abstract String name();
+
+   public abstract double recvAppendRequestCnt();
+
+   public abstract double sendAppendRequestCnt();
+
+   public abstract double sendBandwidthRate();
+
+   public abstract double sendPkgRate();
+
+   public abstract String startTime();
+
+   public abstract String state();
+
+   Self() {
+   }
+
+   @SerializedNames({ "id", "leaderInfo", "name", "recvAppendRequestCnt", "sendAppendRequestCnt", "sendBandwidthRate",
+         "sendPkgRate", "startTime", "state" })
+   public static Self create(String id, LeaderInfo leaderInfo, String name, double recvAppendRequestCnt,
+         double sendAppendRequestCnt, double sendBandwidthRate, double sendPkgRate, String startTime, String state) {
+      return new AutoValue_Self(id, leaderInfo, name, recvAppendRequestCnt, sendAppendRequestCnt, sendBandwidthRate,
+            sendPkgRate, startTime, state);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Store.java
----------------------------------------------------------------------
diff --git a/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Store.java b/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Store.java
new file mode 100644
index 0000000..7bb78a3
--- /dev/null
+++ b/etcd/src/main/java/org/jclouds/etcd/domain/statistics/Store.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd.domain.statistics;
+
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+public abstract class Store {
+
+   public abstract int compareAndSwapFail();
+
+   public abstract int compareAndSwapSuccess();
+
+   public abstract int createFail();
+
+   public abstract int createSuccess();
+
+   public abstract int deleteFail();
+
+   public abstract int deleteSuccess();
+
+   public abstract int expireCount();
+
+   public abstract int getsFail();
+
+   public abstract int getsSuccess();
+
+   public abstract int setsFail();
+
+   public abstract int setsSuccess();
+
+   public abstract int updateFail();
+
+   public abstract int updateSuccess();
+
+   public abstract int watchers();
+
+   Store() {
+   }
+
+   @SerializedNames({ "compareAndSwapFail", "compareAndSwapSuccess", "createFail", "createSuccess", "deleteFail",
+         "deleteSuccess", "expireCount", "getsFail", "getsSuccess", "setsFail", "setsSuccess", "updateFail",
+         "updateSuccess", "watchers" })
+   public static Store create(int compareAndSwapFail, int compareAndSwapSuccess, int createFail, int createSuccess,
+         int deleteFail, int deleteSuccess, int expireCount, int getsFail, int getsSuccess, int setsFail,
+         int setsSuccess, int updateFail, int updateSuccess, int watchers) {
+      return new AutoValue_Store(compareAndSwapFail, compareAndSwapSuccess, createFail, createSuccess, deleteFail,
+            deleteSuccess, expireCount, getsFail, getsSuccess, setsFail, setsSuccess, updateFail, updateSuccess,
+            watchers);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/main/java/org/jclouds/etcd/features/MiscellaneousApi.java
----------------------------------------------------------------------
diff --git a/etcd/src/main/java/org/jclouds/etcd/features/MiscellaneousApi.java b/etcd/src/main/java/org/jclouds/etcd/features/MiscellaneousApi.java
new file mode 100644
index 0000000..ba8d898
--- /dev/null
+++ b/etcd/src/main/java/org/jclouds/etcd/features/MiscellaneousApi.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd.features;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.etcd.domain.miscellaneous.Version;
+import org.jclouds.rest.annotations.SelectJson;
+
+public interface MiscellaneousApi {
+
+   @Named("miscellaneous:version")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Path("/version")
+   @GET
+   Version version();
+
+   @Named("miscellaneous:health")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Path("/health")
+   @SelectJson("health")
+   @GET
+   boolean health();
+
+   @Named("miscellaneous:metrics")
+   @Consumes(MediaType.TEXT_PLAIN)
+   @Path("/metrics")
+   @GET
+   String metrics();
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/main/java/org/jclouds/etcd/features/StatisticsApi.java
----------------------------------------------------------------------
diff --git a/etcd/src/main/java/org/jclouds/etcd/features/StatisticsApi.java b/etcd/src/main/java/org/jclouds/etcd/features/StatisticsApi.java
new file mode 100644
index 0000000..859fac1
--- /dev/null
+++ b/etcd/src/main/java/org/jclouds/etcd/features/StatisticsApi.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd.features;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.etcd.domain.statistics.Leader;
+import org.jclouds.etcd.domain.statistics.Self;
+import org.jclouds.etcd.domain.statistics.Store;
+
+@Consumes(MediaType.APPLICATION_JSON)
+@Path("/{jclouds.api-version}/stats")
+public interface StatisticsApi {
+
+   @Named("statistics:leader")
+   @GET
+   @Path("/leader")
+   Leader leader();
+
+   @Named("statistics:self")
+   @GET
+   @Path("/self")
+   Self self();
+
+   @Named("statistics:store")
+   @GET
+   @Path("/store")
+   Store store();
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/test/java/org/jclouds/etcd/BaseEtcdApiLiveTest.java
----------------------------------------------------------------------
diff --git a/etcd/src/test/java/org/jclouds/etcd/BaseEtcdApiLiveTest.java b/etcd/src/test/java/org/jclouds/etcd/BaseEtcdApiLiveTest.java
new file mode 100644
index 0000000..ac7431d
--- /dev/null
+++ b/etcd/src/test/java/org/jclouds/etcd/BaseEtcdApiLiveTest.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd;
+
+import java.util.Properties;
+
+import org.jclouds.Constants;
+import org.jclouds.apis.BaseApiLiveTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+
+@Test(groups = "live")
+public class BaseEtcdApiLiveTest extends BaseApiLiveTest<EtcdApi> {
+
+   public BaseEtcdApiLiveTest() {
+      provider = "etcd";
+   }
+
+   @Override
+   protected Iterable<Module> setupModules() {
+      return ImmutableSet.<Module> of(getLoggingModule());
+   }
+
+   @Override
+   protected Properties setupProperties() {
+      Properties overrides = super.setupProperties();
+      overrides.setProperty(Constants.PROPERTY_MAX_RETRIES, "0");
+      return overrides;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/test/java/org/jclouds/etcd/EtcdApiMetadataTest.java
----------------------------------------------------------------------
diff --git a/etcd/src/test/java/org/jclouds/etcd/EtcdApiMetadataTest.java b/etcd/src/test/java/org/jclouds/etcd/EtcdApiMetadataTest.java
new file mode 100644
index 0000000..475a5b5
--- /dev/null
+++ b/etcd/src/test/java/org/jclouds/etcd/EtcdApiMetadataTest.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.HashSet;
+import org.jclouds.View;
+import org.jclouds.apis.ApiMetadata;
+import org.jclouds.apis.Apis;
+import org.jclouds.apis.internal.BaseApiMetadataTest;
+import org.testng.annotations.Test;
+
+import com.google.common.reflect.TypeToken;
+
+/**
+ * Unit tests for the {@link EtcdApiMetadata} class.
+ */
+@Test(groups = "unit", testName = "EtcdApiMetadataTest")
+public class EtcdApiMetadataTest extends BaseApiMetadataTest {
+
+   public EtcdApiMetadataTest() {
+      super(new EtcdApiMetadata(), new HashSet<TypeToken<? extends View>>());
+   }
+
+   public void testEtcdApiRegistered() {
+      ApiMetadata api = Apis.withId("etcd");
+
+      assertNotNull(api);
+      assertTrue(api instanceof EtcdApiMetadata);
+      assertEquals(api.getId(), "etcd");
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/test/java/org/jclouds/etcd/features/MiscellaneousApiLiveTest.java
----------------------------------------------------------------------
diff --git a/etcd/src/test/java/org/jclouds/etcd/features/MiscellaneousApiLiveTest.java b/etcd/src/test/java/org/jclouds/etcd/features/MiscellaneousApiLiveTest.java
new file mode 100644
index 0000000..ec955c3
--- /dev/null
+++ b/etcd/src/test/java/org/jclouds/etcd/features/MiscellaneousApiLiveTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd.features;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import org.jclouds.etcd.BaseEtcdApiLiveTest;
+import org.jclouds.etcd.domain.miscellaneous.Version;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "MiscellaneousApiLiveTest")
+public class MiscellaneousApiLiveTest extends BaseEtcdApiLiveTest {
+
+   private final String versionRegex = "^\\d+\\.\\d+\\.\\d+$";
+
+   @Test
+   public void testGetVersion() {
+      Version version = api().version();
+      assertNotNull(version);
+      assertTrue(version.etcdServer().matches(versionRegex));
+      assertTrue(version.etcdCluster().matches(versionRegex));
+   }
+
+   @Test
+   public void testGetHealth() {
+      boolean health = api().health();
+      assertTrue(health);
+   }
+
+   @Test
+   public void testGetMetrics() {
+      String metrics = api().metrics();
+      assertNotNull(metrics);
+   }
+
+   private MiscellaneousApi api() {
+      return api.miscellaneousApi();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/test/java/org/jclouds/etcd/features/MiscellaneousApiMockTest.java
----------------------------------------------------------------------
diff --git a/etcd/src/test/java/org/jclouds/etcd/features/MiscellaneousApiMockTest.java b/etcd/src/test/java/org/jclouds/etcd/features/MiscellaneousApiMockTest.java
new file mode 100644
index 0000000..abd239d
--- /dev/null
+++ b/etcd/src/test/java/org/jclouds/etcd/features/MiscellaneousApiMockTest.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd.features;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.etcd.EtcdApi;
+import org.jclouds.etcd.domain.miscellaneous.Version;
+import org.jclouds.etcd.internal.BaseEtcdMockTest;
+import org.testng.annotations.Test;
+
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+
+/**
+ * Mock tests for the {@link org.jclouds.etcd.features.MiscellaneousApi} class.
+ */
+@Test(groups = "unit", testName = "MiscellaneousApiMockTest")
+public class MiscellaneousApiMockTest extends BaseEtcdMockTest {
+
+   private final String versionRegex = "^\\d+\\.\\d+\\.\\d+$";
+
+   public void testGetVersion() throws Exception {
+      MockWebServer server = mockEtcdJavaWebServer();
+
+      server.enqueue(new MockResponse().setBody(payloadFromResource("/version.json")).setResponseCode(200));
+      EtcdApi etcdJavaApi = api(server.getUrl("/"));
+      MiscellaneousApi api = etcdJavaApi.miscellaneousApi();
+      try {
+         Version version = api.version();
+         assertNotNull(version);
+         assertTrue(version.etcdServer().matches(versionRegex));
+         assertTrue(version.etcdCluster().matches(versionRegex));
+         assertSent(server, "GET", "/version");
+      } finally {
+         etcdJavaApi.close();
+         server.shutdown();
+      }
+   }
+
+   public void testGetHealth() throws Exception {
+      MockWebServer server = mockEtcdJavaWebServer();
+
+      server.enqueue(new MockResponse().setBody(payloadFromResource("/health.json")).setResponseCode(200));
+      EtcdApi etcdJavaApi = api(server.getUrl("/"));
+      MiscellaneousApi api = etcdJavaApi.miscellaneousApi();
+      try {
+         boolean health = api.health();
+         assertTrue(health);
+         assertSent(server, "GET", "/health");
+      } finally {
+         etcdJavaApi.close();
+         server.shutdown();
+      }
+   }
+
+   public void testGetMetrics() throws Exception {
+      MockWebServer server = mockEtcdJavaWebServer();
+
+      server.enqueue(new MockResponse().setBody(payloadFromResource("/metrics.txt")).setResponseCode(200));
+      EtcdApi etcdJavaApi = api(server.getUrl("/"));
+      MiscellaneousApi api = etcdJavaApi.miscellaneousApi();
+      try {
+         String metrics = api.metrics();
+         assertNotNull(metrics);
+         assertSentAcceptText(server, "GET", "/metrics");
+      } finally {
+         etcdJavaApi.close();
+         server.shutdown();
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/test/java/org/jclouds/etcd/features/StatisticsApiLiveTest.java
----------------------------------------------------------------------
diff --git a/etcd/src/test/java/org/jclouds/etcd/features/StatisticsApiLiveTest.java b/etcd/src/test/java/org/jclouds/etcd/features/StatisticsApiLiveTest.java
new file mode 100644
index 0000000..b02370d
--- /dev/null
+++ b/etcd/src/test/java/org/jclouds/etcd/features/StatisticsApiLiveTest.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd.features;
+
+import static org.testng.Assert.assertNotNull;
+import org.jclouds.etcd.BaseEtcdApiLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "StatisticsApiLiveTest")
+public class StatisticsApiLiveTest extends BaseEtcdApiLiveTest {
+
+   @Test
+   public void testGetLeader() throws Exception {
+      assertNotNull(api().leader());
+   }
+
+   @Test
+   public void testGetSelf() throws Exception {
+      assertNotNull(api().self());
+   }
+
+   @Test
+   public void testGetStore() throws Exception {
+      assertNotNull(api().store());
+   }
+
+   private StatisticsApi api() {
+      return api.statisticsApi();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/test/java/org/jclouds/etcd/features/StatisticsApiMockTest.java
----------------------------------------------------------------------
diff --git a/etcd/src/test/java/org/jclouds/etcd/features/StatisticsApiMockTest.java b/etcd/src/test/java/org/jclouds/etcd/features/StatisticsApiMockTest.java
new file mode 100644
index 0000000..fc5bdc7
--- /dev/null
+++ b/etcd/src/test/java/org/jclouds/etcd/features/StatisticsApiMockTest.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd.features;
+
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertNotNull;
+
+import org.jclouds.etcd.EtcdApi;
+import org.jclouds.etcd.EtcdApiMetadata;
+import org.jclouds.etcd.domain.statistics.Leader;
+import org.jclouds.etcd.domain.statistics.Self;
+import org.jclouds.etcd.domain.statistics.Store;
+import org.jclouds.etcd.internal.BaseEtcdMockTest;
+
+import org.testng.annotations.Test;
+
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+
+/**
+ * Mock tests for the {@link org.jclouds.etcd.features.StatisticsApi} class.
+ */
+@Test(groups = "unit", testName = "StatisticsApiMockTest")
+public class StatisticsApiMockTest extends BaseEtcdMockTest {
+
+   public void testGetLeader() throws Exception {
+      MockWebServer server = mockEtcdJavaWebServer();
+
+      server.enqueue(new MockResponse().setBody(payloadFromResource("/leader.json")).setResponseCode(200));
+      EtcdApi etcdJavaApi = api(server.getUrl("/"));
+      StatisticsApi api = etcdJavaApi.statisticsApi();
+      try {
+         Leader leader = api.leader();
+         assertNotNull(leader);
+         assertTrue(leader.followers().size() == 2);
+         assertTrue(leader.leader().equals("924e2e83e93f2560"));
+         assertSent(server, "GET", "/" + EtcdApiMetadata.API_VERSION + "/stats/leader");
+      } finally {
+         etcdJavaApi.close();
+         server.shutdown();
+      }
+   }
+
+   public void testGetSelf() throws Exception {
+      MockWebServer server = mockEtcdJavaWebServer();
+
+      server.enqueue(new MockResponse().setBody(payloadFromResource("/self.json")).setResponseCode(200));
+      EtcdApi etcdJavaApi = api(server.getUrl("/"));
+      StatisticsApi api = etcdJavaApi.statisticsApi();
+      try {
+         Self self = api.self();
+         assertNotNull(self);
+         assertTrue(self.leaderInfo().leader().equals("924e2e83e93f2560"));
+         assertSent(server, "GET", "/" + EtcdApiMetadata.API_VERSION + "/stats/self");
+      } finally {
+         etcdJavaApi.close();
+         server.shutdown();
+      }
+   }
+
+   public void testGetStore() throws Exception {
+      MockWebServer server = mockEtcdJavaWebServer();
+
+      server.enqueue(new MockResponse().setBody(payloadFromResource("/store.json")).setResponseCode(200));
+      EtcdApi etcdJavaApi = api(server.getUrl("/"));
+      StatisticsApi api = etcdJavaApi.statisticsApi();
+      try {
+         Store store = api.store();
+         assertNotNull(store);
+         assertTrue(store.getsSuccess() == 75);
+         assertSent(server, "GET", "/" + EtcdApiMetadata.API_VERSION + "/stats/store");
+      } finally {
+         etcdJavaApi.close();
+         server.shutdown();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/test/java/org/jclouds/etcd/internal/BaseEtcdMockTest.java
----------------------------------------------------------------------
diff --git a/etcd/src/test/java/org/jclouds/etcd/internal/BaseEtcdMockTest.java b/etcd/src/test/java/org/jclouds/etcd/internal/BaseEtcdMockTest.java
new file mode 100644
index 0000000..8cd85eb
--- /dev/null
+++ b/etcd/src/test/java/org/jclouds/etcd/internal/BaseEtcdMockTest.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jclouds.etcd.internal;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.jclouds.util.Strings2.toStringAndClose;
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Properties;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.Constants;
+import org.jclouds.ContextBuilder;
+import org.jclouds.etcd.EtcdApi;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Throwables;
+import com.google.gson.JsonParser;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+import com.squareup.okhttp.mockwebserver.RecordedRequest;
+
+/**
+ * Base class for all Etcd mock tests.
+ */
+public class BaseEtcdMockTest {
+
+   protected String provider;
+   private final JsonParser parser = new JsonParser();
+
+   public BaseEtcdMockTest() {
+      provider = "etcd";
+   }
+
+   public EtcdApi api(URL url) {
+      return ContextBuilder.newBuilder(provider).endpoint(url.toString()).overrides(setupProperties())
+            .buildApi(EtcdApi.class);
+   }
+
+   protected Properties setupProperties() {
+      Properties properties = new Properties();
+      properties.setProperty(Constants.PROPERTY_MAX_RETRIES, "0");
+      return properties;
+   }
+
+   public static MockWebServer mockEtcdJavaWebServer() throws IOException {
+      MockWebServer server = new MockWebServer();
+      server.play();
+      return server;
+   }
+
+   public String payloadFromResource(String resource) {
+      try {
+         return new String(toStringAndClose(getClass().getResourceAsStream(resource)).getBytes(Charsets.UTF_8));
+      } catch (IOException e) {
+         throw Throwables.propagate(e);
+      }
+   }
+
+   protected RecordedRequest assertSent(MockWebServer server, String method, String path) throws InterruptedException {
+      RecordedRequest request = server.takeRequest();
+      assertThat(request.getMethod()).isEqualTo(method);
+      assertThat(request.getPath()).isEqualTo(path);
+      assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.APPLICATION_JSON);
+      return request;
+   }
+
+   protected RecordedRequest assertSentAcceptText(MockWebServer server, String method, String path)
+         throws InterruptedException {
+      RecordedRequest request = server.takeRequest();
+      assertThat(request.getMethod()).isEqualTo(method);
+      assertThat(request.getPath()).isEqualTo(path);
+      assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.TEXT_PLAIN);
+      return request;
+   }
+
+   protected RecordedRequest assertSent(MockWebServer server, String method, String path, String json)
+         throws InterruptedException {
+      RecordedRequest request = assertSent(server, method, path);
+      assertEquals(request.getHeader("Content-Type"), APPLICATION_JSON);
+      assertEquals(parser.parse(request.getUtf8Body()), parser.parse(json));
+      return request;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/test/resources/health.json
----------------------------------------------------------------------
diff --git a/etcd/src/test/resources/health.json b/etcd/src/test/resources/health.json
new file mode 100644
index 0000000..fdc9176
--- /dev/null
+++ b/etcd/src/test/resources/health.json
@@ -0,0 +1 @@
+{"health": "true"}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/test/resources/leader.json
----------------------------------------------------------------------
diff --git a/etcd/src/test/resources/leader.json b/etcd/src/test/resources/leader.json
new file mode 100644
index 0000000..496f904
--- /dev/null
+++ b/etcd/src/test/resources/leader.json
@@ -0,0 +1,31 @@
+{
+    "followers": {
+        "6e3bd23ae5f1eae0": {
+            "counts": {
+                "fail": 0,
+                "success": 745
+            },
+            "latency": {
+                "average": 0.017039507382550306,
+                "current": 0.000138,
+                "maximum": 1.007649,
+                "minimum": 0,
+                "standardDeviation": 0.05289178277920594
+            }
+        },
+        "a8266ecf031671f3": {
+            "counts": {
+                "fail": 0,
+                "success": 735
+            },
+            "latency": {
+                "average": 0.012124141496598642,
+                "current": 0.000559,
+                "maximum": 0.791547,
+                "minimum": 0,
+                "standardDeviation": 0.04187900156583733
+            }
+        }
+    },
+    "leader": "924e2e83e93f2560"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/test/resources/metrics.txt
----------------------------------------------------------------------
diff --git a/etcd/src/test/resources/metrics.txt b/etcd/src/test/resources/metrics.txt
new file mode 100644
index 0000000..e59f2d6
--- /dev/null
+++ b/etcd/src/test/resources/metrics.txt
@@ -0,0 +1,160 @@
+# HELP etcd_rafthttp_message_sent_latency_microseconds message sent latency distributions.
+# TYPE etcd_rafthttp_message_sent_latency_microseconds summary
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgApp",remoteID="96d5f4741cf7499e",sendingType="message",quantile="0.5"} NaN
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgApp",remoteID="96d5f4741cf7499e",sendingType="message",quantile="0.9"} NaN
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgApp",remoteID="96d5f4741cf7499e",sendingType="message",quantile="0.99"} NaN
+etcd_rafthttp_message_sent_latency_microseconds_sum{msgType="MsgApp",remoteID="96d5f4741cf7499e",sendingType="message"} 84
+etcd_rafthttp_message_sent_latency_microseconds_count{msgType="MsgApp",remoteID="96d5f4741cf7499e",sendingType="message"} 1
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgApp",remoteID="96d5f4741cf7499e",sendingType="msgappv2",quantile="0.5"} 50
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgApp",remoteID="96d5f4741cf7499e",sendingType="msgappv2",quantile="0.9"} 78
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgApp",remoteID="96d5f4741cf7499e",sendingType="msgappv2",quantile="0.99"} 98
+etcd_rafthttp_message_sent_latency_microseconds_sum{msgType="MsgApp",remoteID="96d5f4741cf7499e",sendingType="msgappv2"} 2.045591e+06
+etcd_rafthttp_message_sent_latency_microseconds_count{msgType="MsgApp",remoteID="96d5f4741cf7499e",sendingType="msgappv2"} 34607
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgApp",remoteID="f992d9b00b6adf2f",sendingType="message",quantile="0.5"} NaN
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgApp",remoteID="f992d9b00b6adf2f",sendingType="message",quantile="0.9"} NaN
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgApp",remoteID="f992d9b00b6adf2f",sendingType="message",quantile="0.99"} NaN
+etcd_rafthttp_message_sent_latency_microseconds_sum{msgType="MsgApp",remoteID="f992d9b00b6adf2f",sendingType="message"} 45
+etcd_rafthttp_message_sent_latency_microseconds_count{msgType="MsgApp",remoteID="f992d9b00b6adf2f",sendingType="message"} 1
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgApp",remoteID="f992d9b00b6adf2f",sendingType="msgappv2",quantile="0.5"} 35
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgApp",remoteID="f992d9b00b6adf2f",sendingType="msgappv2",quantile="0.9"} 51
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgApp",remoteID="f992d9b00b6adf2f",sendingType="msgappv2",quantile="0.99"} 83
+etcd_rafthttp_message_sent_latency_microseconds_sum{msgType="MsgApp",remoteID="f992d9b00b6adf2f",sendingType="msgappv2"} 1.426621e+06
+etcd_rafthttp_message_sent_latency_microseconds_count{msgType="MsgApp",remoteID="f992d9b00b6adf2f",sendingType="msgappv2"} 34664
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgHeartbeat",remoteID="96d5f4741cf7499e",sendingType="message",quantile="0.5"} 60
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgHeartbeat",remoteID="96d5f4741cf7499e",sendingType="message",quantile="0.9"} 91
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgHeartbeat",remoteID="96d5f4741cf7499e",sendingType="message",quantile="0.99"} 101
+etcd_rafthttp_message_sent_latency_microseconds_sum{msgType="MsgHeartbeat",remoteID="96d5f4741cf7499e",sendingType="message"} 548492
+etcd_rafthttp_message_sent_latency_microseconds_count{msgType="MsgHeartbeat",remoteID="96d5f4741cf7499e",sendingType="message"} 7076
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgHeartbeat",remoteID="f992d9b00b6adf2f",sendingType="message",quantile="0.5"} 39
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgHeartbeat",remoteID="f992d9b00b6adf2f",sendingType="message",quantile="0.9"} 58
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgHeartbeat",remoteID="f992d9b00b6adf2f",sendingType="message",quantile="0.99"} 93
+etcd_rafthttp_message_sent_latency_microseconds_sum{msgType="MsgHeartbeat",remoteID="f992d9b00b6adf2f",sendingType="message"} 335711
+etcd_rafthttp_message_sent_latency_microseconds_count{msgType="MsgHeartbeat",remoteID="f992d9b00b6adf2f",sendingType="message"} 7076
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgLinkHeartbeat",remoteID="0",sendingType="message",quantile="0.5"} 53
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgLinkHeartbeat",remoteID="0",sendingType="message",quantile="0.9"} 65
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgLinkHeartbeat",remoteID="0",sendingType="message",quantile="0.99"} 71
+etcd_rafthttp_message_sent_latency_microseconds_sum{msgType="MsgLinkHeartbeat",remoteID="0",sendingType="message"} 455136
+etcd_rafthttp_message_sent_latency_microseconds_count{msgType="MsgLinkHeartbeat",remoteID="0",sendingType="message"} 8578
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgLinkHeartbeat",remoteID="0",sendingType="msgappv2",quantile="0.5"} 54
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgLinkHeartbeat",remoteID="0",sendingType="msgappv2",quantile="0.9"} 69
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgLinkHeartbeat",remoteID="0",sendingType="msgappv2",quantile="0.99"} 93
+etcd_rafthttp_message_sent_latency_microseconds_sum{msgType="MsgLinkHeartbeat",remoteID="0",sendingType="msgappv2"} 482458
+etcd_rafthttp_message_sent_latency_microseconds_count{msgType="MsgLinkHeartbeat",remoteID="0",sendingType="msgappv2"} 8578
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgVote",remoteID="96d5f4741cf7499e",sendingType="message",quantile="0.5"} NaN
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgVote",remoteID="96d5f4741cf7499e",sendingType="message",quantile="0.9"} NaN
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgVote",remoteID="96d5f4741cf7499e",sendingType="message",quantile="0.99"} NaN
+etcd_rafthttp_message_sent_latency_microseconds_sum{msgType="MsgVote",remoteID="96d5f4741cf7499e",sendingType="message"} 162
+etcd_rafthttp_message_sent_latency_microseconds_count{msgType="MsgVote",remoteID="96d5f4741cf7499e",sendingType="message"} 1
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgVote",remoteID="f992d9b00b6adf2f",sendingType="message",quantile="0.5"} NaN
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgVote",remoteID="f992d9b00b6adf2f",sendingType="message",quantile="0.9"} NaN
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgVote",remoteID="f992d9b00b6adf2f",sendingType="message",quantile="0.99"} NaN
+etcd_rafthttp_message_sent_latency_microseconds_sum{msgType="MsgVote",remoteID="f992d9b00b6adf2f",sendingType="message"} 57
+etcd_rafthttp_message_sent_latency_microseconds_count{msgType="MsgVote",remoteID="f992d9b00b6adf2f",sendingType="message"} 1
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgVoteResp",remoteID="96d5f4741cf7499e",sendingType="message",quantile="0.5"} NaN
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgVoteResp",remoteID="96d5f4741cf7499e",sendingType="message",quantile="0.9"} NaN
+etcd_rafthttp_message_sent_latency_microseconds{msgType="MsgVoteResp",remoteID="96d5f4741cf7499e",sendingType="message",quantile="0.99"} NaN
+etcd_rafthttp_message_sent_latency_microseconds_sum{msgType="MsgVoteResp",remoteID="96d5f4741cf7499e",sendingType="message"} 54
+etcd_rafthttp_message_sent_latency_microseconds_count{msgType="MsgVoteResp",remoteID="96d5f4741cf7499e",sendingType="message"} 1
+# HELP etcd_server_file_descriptors_used_total The total number of file descriptors used.
+# TYPE etcd_server_file_descriptors_used_total gauge
+etcd_server_file_descriptors_used_total 18
+# HELP etcd_server_pending_proposal_total The total number of pending proposals.
+# TYPE etcd_server_pending_proposal_total gauge
+etcd_server_pending_proposal_total 0
+# HELP etcd_server_proposal_durations_milliseconds The latency distributions of committing proposal.
+# TYPE etcd_server_proposal_durations_milliseconds summary
+etcd_server_proposal_durations_milliseconds{quantile="0.5"} NaN
+etcd_server_proposal_durations_milliseconds{quantile="0.9"} NaN
+etcd_server_proposal_durations_milliseconds{quantile="0.99"} NaN
+etcd_server_proposal_durations_milliseconds_sum 3678
+etcd_server_proposal_durations_milliseconds_count 2
+# HELP etcd_server_proposal_failed_total The total number of failed proposals.
+# TYPE etcd_server_proposal_failed_total counter
+etcd_server_proposal_failed_total 1
+# HELP etcd_snapshot_save_total_durations_microseconds The total latency distributions of save called by snapshot.
+# TYPE etcd_snapshot_save_total_durations_microseconds summary
+etcd_snapshot_save_total_durations_microseconds{quantile="0.5"} NaN
+etcd_snapshot_save_total_durations_microseconds{quantile="0.9"} NaN
+etcd_snapshot_save_total_durations_microseconds{quantile="0.99"} NaN
+etcd_snapshot_save_total_durations_microseconds_sum 258
+etcd_snapshot_save_total_durations_microseconds_count 1
+# HELP etcd_store_expires_total Total number of expired keys.
+# TYPE etcd_store_expires_total counter
+etcd_store_expires_total 0
+# HELP etcd_store_reads_total Total number of reads action by (get/getRecursive), local to this member.
+# TYPE etcd_store_reads_total counter
+etcd_store_reads_total{action="getRecursive"} 5
+# HELP etcd_store_watch_requests_total Total number of incoming watch requests (new or reestablished).
+# TYPE etcd_store_watch_requests_total counter
+etcd_store_watch_requests_total 0
+# HELP etcd_store_watchers Count of currently active watchers.
+# TYPE etcd_store_watchers gauge
+etcd_store_watchers 0
+# HELP etcd_store_writes_total Total number of writes (e.g. set/compareAndDelete) seen by this member.
+# TYPE etcd_store_writes_total counter
+etcd_store_writes_total{action="create"} 3
+etcd_store_writes_total{action="set"} 4
+# HELP etcd_wal_fsync_durations_microseconds The latency distributions of fsync called by wal.
+# TYPE etcd_wal_fsync_durations_microseconds summary
+etcd_wal_fsync_durations_microseconds{quantile="0.5"} 41299
+etcd_wal_fsync_durations_microseconds{quantile="0.9"} 120044
+etcd_wal_fsync_durations_microseconds{quantile="0.99"} 563066
+etcd_wal_fsync_durations_microseconds_sum 1.862452899e+09
+etcd_wal_fsync_durations_microseconds_count 27906
+# HELP etcd_wal_last_index_saved The index of the last entry saved by wal.
+# TYPE etcd_wal_last_index_saved gauge
+etcd_wal_last_index_saved 13970
+# HELP go_gc_duration_seconds A summary of the GC invocation durations.
+# TYPE go_gc_duration_seconds summary
+go_gc_duration_seconds{quantile="0"} 0.000199168
+go_gc_duration_seconds{quantile="0.25"} 0.011117938
+go_gc_duration_seconds{quantile="0.5"} 0.013050367
+go_gc_duration_seconds{quantile="0.75"} 0.015054046000000001
+go_gc_duration_seconds{quantile="1"} 0.020298544
+go_gc_duration_seconds_sum 0.8452645520000001
+go_gc_duration_seconds_count 71
+# HELP go_goroutines Number of goroutines that currently exist.
+# TYPE go_goroutines gauge
+go_goroutines 69
+# HELP http_request_duration_microseconds The HTTP request latencies in microseconds.
+# TYPE http_request_duration_microseconds summary
+http_request_duration_microseconds{handler="prometheus",quantile="0.5"} NaN
+http_request_duration_microseconds{handler="prometheus",quantile="0.9"} NaN
+http_request_duration_microseconds{handler="prometheus",quantile="0.99"} NaN
+http_request_duration_microseconds_sum{handler="prometheus"} 11850.234
+http_request_duration_microseconds_count{handler="prometheus"} 2
+# HELP http_request_size_bytes The HTTP request sizes in bytes.
+# TYPE http_request_size_bytes summary
+http_request_size_bytes{handler="prometheus",quantile="0.5"} NaN
+http_request_size_bytes{handler="prometheus",quantile="0.9"} NaN
+http_request_size_bytes{handler="prometheus",quantile="0.99"} NaN
+http_request_size_bytes_sum{handler="prometheus"} 680
+http_request_size_bytes_count{handler="prometheus"} 2
+# HELP http_requests_total Total number of HTTP requests made.
+# TYPE http_requests_total counter
+http_requests_total{code="200",handler="prometheus",method="get"} 2
+# HELP http_response_size_bytes The HTTP response sizes in bytes.
+# TYPE http_response_size_bytes summary
+http_response_size_bytes{handler="prometheus",quantile="0.5"} NaN
+http_response_size_bytes{handler="prometheus",quantile="0.9"} NaN
+http_response_size_bytes{handler="prometheus",quantile="0.99"} NaN
+http_response_size_bytes_sum{handler="prometheus"} 3494
+http_response_size_bytes_count{handler="prometheus"} 2
+# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
+# TYPE process_cpu_seconds_total counter
+process_cpu_seconds_total 48.72
+# HELP process_max_fds Maximum number of open file descriptors.
+# TYPE process_max_fds gauge
+process_max_fds 1024
+# HELP process_open_fds Number of open file descriptors.
+# TYPE process_open_fds gauge
+process_open_fds 19
+# HELP process_resident_memory_bytes Resident memory size in bytes.
+# TYPE process_resident_memory_bytes gauge
+process_resident_memory_bytes 2.8459008e+07
+# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
+# TYPE process_start_time_seconds gauge
+process_start_time_seconds 1.43810894456e+09
+# HELP process_virtual_memory_bytes Virtual memory size in bytes.
+# TYPE process_virtual_memory_bytes gauge
+process_virtual_memory_bytes 3.749888e+07
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/test/resources/self.json
----------------------------------------------------------------------
diff --git a/etcd/src/test/resources/self.json b/etcd/src/test/resources/self.json
new file mode 100644
index 0000000..72b15d5
--- /dev/null
+++ b/etcd/src/test/resources/self.json
@@ -0,0 +1,15 @@
+{
+    "id": "924e2e83e93f2560",
+    "leaderInfo": {
+        "leader": "924e2e83e93f2560",
+        "startTime": "2015-02-09T11:38:30.177534688-08:00",
+        "uptime": "9m33.891343412s"
+    },
+    "name": "infra3",
+    "recvAppendRequestCnt": 0,
+    "sendAppendRequestCnt": 6535,
+    "sendBandwidthRate": 824.1758351191694,
+    "sendPkgRate": 11.111234716807138,
+    "startTime": "2015-02-09T11:38:28.972034204-08:00",
+    "state": "StateLeader"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/test/resources/store.json
----------------------------------------------------------------------
diff --git a/etcd/src/test/resources/store.json b/etcd/src/test/resources/store.json
new file mode 100644
index 0000000..03e6e3d
--- /dev/null
+++ b/etcd/src/test/resources/store.json
@@ -0,0 +1,16 @@
+{
+    "compareAndSwapFail": 0,
+    "compareAndSwapSuccess": 0,
+    "createFail": 0,
+    "createSuccess": 2,
+    "deleteFail": 0,
+    "deleteSuccess": 0,
+    "expireCount": 0,
+    "getsFail": 4,
+    "getsSuccess": 75,
+    "setsFail": 2,
+    "setsSuccess": 4,
+    "updateFail": 0,
+    "updateSuccess": 0,
+    "watchers": 0
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/etcd/src/test/resources/version.json
----------------------------------------------------------------------
diff --git a/etcd/src/test/resources/version.json b/etcd/src/test/resources/version.json
new file mode 100644
index 0000000..f5c5e12
--- /dev/null
+++ b/etcd/src/test/resources/version.json
@@ -0,0 +1,4 @@
+{
+	"etcdserver":"2.1.1",
+	"etcdcluster":"2.1.0"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9cd3cfa5/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 023f3e4..2a6bf43 100644
--- a/pom.xml
+++ b/pom.xml
@@ -66,6 +66,7 @@
 
   <modules>
     <module>azurecompute</module>
+    <module>etcd</module>
     <module>docker</module>
     <module>cdmi</module>
     <module>cloudsigma2</module>