You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by jd...@apache.org on 2014/07/02 20:47:05 UTC

git commit: Added ConsolesApi extension for openstack-nova

Repository: jclouds
Updated Branches:
  refs/heads/master e19c5e9fb -> b259af48c


Added ConsolesApi extension for openstack-nova


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

Branch: refs/heads/master
Commit: b259af48c0b1b5af65eeb3ebe3de8fec838d2ce4
Parents: e19c5e9
Author: Epimenidis Voutsakis <pi...@gmail.com>
Authored: Mon Apr 7 21:14:01 2014 +0300
Committer: Jeremy Daggett <jd...@apache.org>
Committed: Wed Jul 2 11:39:52 2014 -0700

----------------------------------------------------------------------
 .../jclouds/openstack/nova/v2_0/NovaApi.java    |   8 +
 .../openstack/nova/v2_0/NovaAsyncApi.java       |   8 +
 .../v2_0/binders/BindConsoleToJsonPayload.java  |  63 ++++++++
 .../nova/v2_0/config/NovaRestClientModule.java  |   3 +
 .../openstack/nova/v2_0/domain/Console.java     | 161 +++++++++++++++++++
 .../nova/v2_0/extensions/ConsolesApi.java       |  41 +++++
 .../nova/v2_0/extensions/ConsolesAsyncApi.java  |  68 ++++++++
 .../v2_0/extensions/ExtensionNamespaces.java    |   5 +
 .../openstack/nova/v2_0/features/ServerApi.java |   3 +-
 .../v2_0/extensions/ConsolesApiLiveTest.java    |  64 ++++++++
 .../v2_0/extensions/ConsolesApiMockTest.java    | 145 +++++++++++++++++
 .../nova/v2_0/parse/ParseNOVNCConsoleTest.java  |  69 ++++++++
 .../nova/v2_0/parse/ParseRDPConsoleTest.java    |  70 ++++++++
 .../nova/v2_0/parse/ParseSPICEConsoleTest.java  |  70 ++++++++
 .../nova/v2_0/parse/ParseXVPVNCConsoleTest.java |  68 ++++++++
 .../src/test/resources/novnc_console.json       |   7 +
 .../src/test/resources/rdp_console.json         |   7 +
 .../src/test/resources/spice_console.json       |   7 +
 .../src/test/resources/xvpvnc_console.json      |   7 +
 19 files changed, 872 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/b259af48/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaApi.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaApi.java
index 42f623e..aaa18c2 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaApi.java
@@ -22,6 +22,7 @@ import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.location.Zone;
 import org.jclouds.location.functions.ZoneToEndpoint;
 import org.jclouds.openstack.nova.v2_0.extensions.AvailabilityZoneApi;
+import org.jclouds.openstack.nova.v2_0.extensions.ConsolesApi;
 import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsApi;
 import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPApi;
 import org.jclouds.openstack.nova.v2_0.extensions.HostAdministrationApi;
@@ -196,4 +197,11 @@ public interface NovaApi extends Closeable {
    Optional<? extends VolumeTypeApi> getVolumeTypeExtensionForZone(
          @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
 
+   /**
+    * Provides synchronous access to Console features.
+    */
+   @Delegate
+   Optional<? extends ConsolesApi> getConsolesExtensionForZone(
+         @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b259af48/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaAsyncApi.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaAsyncApi.java
index 5413afd..2ac9959 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaAsyncApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaAsyncApi.java
@@ -23,6 +23,7 @@ import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.location.Zone;
 import org.jclouds.location.functions.ZoneToEndpoint;
 import org.jclouds.openstack.nova.v2_0.extensions.AvailabilityZoneAsyncApi;
+import org.jclouds.openstack.nova.v2_0.extensions.ConsolesAsyncApi;
 import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsAsyncApi;
 import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPAsyncApi;
 import org.jclouds.openstack.nova.v2_0.extensions.HostAdministrationAsyncApi;
@@ -202,4 +203,11 @@ public interface NovaAsyncApi extends Closeable {
    Optional<? extends VolumeTypeAsyncApi> getVolumeTypeExtensionForZone(
          @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
 
+   /**
+    * Provides asynchronous access to Volume Type features.
+    */
+   @Delegate
+   Optional<? extends ConsolesAsyncApi> getConsolesExtensionForZone(
+         @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b259af48/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/binders/BindConsoleToJsonPayload.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/binders/BindConsoleToJsonPayload.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/binders/BindConsoleToJsonPayload.java
new file mode 100644
index 0000000..82f69f3
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/binders/BindConsoleToJsonPayload.java
@@ -0,0 +1,63 @@
+/*
+ * 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.openstack.nova.v2_0.binders;
+
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.nova.v2_0.domain.Console;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSortedMap;
+
+@Singleton
+public class BindConsoleToJsonPayload extends BindToJsonPayload {
+
+   @Inject
+   public BindConsoleToJsonPayload(Json jsonBinder) {
+      super(jsonBinder);
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
+      String action;
+
+      Console.Type type = (Console.Type) postParams.get("type");
+
+      switch (type) {
+         case NOVNC:
+         case XVPVNC:
+            action = "os-getVNCConsole";
+            break;
+         case SPICE_HTML5:
+            action = "os-getSPICEConsole";
+            break;
+         case RDP_HTML5:
+            action = "os-getRDPConsole";
+            break;
+         default:
+            throw new IllegalArgumentException("Invalid type: " + type);
+      }
+
+      return bindToRequest(request, ImmutableMap.of(action, ImmutableSortedMap.copyOf(postParams)));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b259af48/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaRestClientModule.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaRestClientModule.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaRestClientModule.java
index 2a0f548..799cf15 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaRestClientModule.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaRestClientModule.java
@@ -33,6 +33,8 @@ import org.jclouds.openstack.nova.v2_0.NovaApi;
 import org.jclouds.openstack.nova.v2_0.NovaAsyncApi;
 import org.jclouds.openstack.nova.v2_0.extensions.AvailabilityZoneApi;
 import org.jclouds.openstack.nova.v2_0.extensions.AvailabilityZoneAsyncApi;
+import org.jclouds.openstack.nova.v2_0.extensions.ConsolesApi;
+import org.jclouds.openstack.nova.v2_0.extensions.ConsolesAsyncApi;
 import org.jclouds.openstack.nova.v2_0.extensions.ExtensionNamespaces;
 import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsApi;
 import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsAsyncApi;
@@ -112,6 +114,7 @@ public class NovaRestClientModule<S extends NovaApi, A extends NovaAsyncApi> ext
          .put(VolumeApi.class, VolumeAsyncApi.class)
          .put(VolumeAttachmentApi.class, VolumeAttachmentAsyncApi.class)
          .put(VolumeTypeApi.class, VolumeTypeAsyncApi.class)
+         .put(ConsolesApi.class, ConsolesAsyncApi.class)
          .build();
 
    @SuppressWarnings("unchecked")

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b259af48/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Console.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Console.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Console.java
new file mode 100644
index 0000000..1c51fbf
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Console.java
@@ -0,0 +1,161 @@
+/*
+ * 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.openstack.nova.v2_0.domain;
+
+import static com.google.common.base.Objects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.beans.ConstructorProperties;
+import java.net.URI;
+
+import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.base.Objects;
+
+/**
+ * Represents an Openstack Console.
+ */
+public class Console {
+   public enum Type {
+      NOVNC("novnc"),
+      XVPVNC("xvpvnc"),
+      SPICE_HTML5("spice-html5"),
+      RDP_HTML5("rdp-html5"),
+      UNRECOGNIZED("unrecognized");
+
+      private final String type;
+
+      Type(String type) {
+         this.type = type;
+      }
+
+      public String type() {
+         return type;
+      }
+
+      /**
+       * Used from jclouds builtin deserializer.
+       */
+      public static Type fromValue(String type) {
+          if (type != null) {
+             for (Type value : Type.values()) {
+                if (type.equals(value.type)) {
+                   return value;
+                }
+             }
+             return UNRECOGNIZED;
+          }
+          return null;
+      }
+
+      @Override
+      public String toString() {
+          return type();
+      }
+   }
+
+   public static Builder<?> builder() {
+      return new ConcreteBuilder();
+   }
+
+   public Builder<?> toBuilder() {
+      return new ConcreteBuilder().fromConsole(this);
+   }
+
+   public abstract static class Builder<T extends Builder<T>> {
+      protected abstract T self();
+
+      protected URI url;
+      protected Type type;
+
+      /**
+       * @see Console#getUrl()
+       */
+      public T url(URI url) {
+         this.url = checkNotNull(url, "url");
+         return self();
+      }
+
+      /**
+       * @see Console#getType()
+       */
+      public T type(Type type) {
+         this.type = type;
+         return self();
+      }
+
+      public Console build() {
+         return new Console(url, type);
+      }
+
+      public T fromConsole(Console in) {
+         return this.url(in.getUrl()).type(in.getType());
+      }
+   }
+
+   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
+      @Override
+      protected ConcreteBuilder self() {
+         return this;
+      }
+   }
+
+   private final URI url;
+   private final Type type;
+
+   @ConstructorProperties({ "url", "type" })
+   protected Console(URI url, Type type) {
+      this.url = checkNotNull(url, "url");
+      this.type = checkNotNull(type, "type");
+   }
+
+   /**
+    * @return the url to use to connect to the server.
+    */
+   public URI getUrl() {
+      return this.url;
+   }
+
+   /**
+    * @return the type of the url
+    */
+   public Type getType() {
+      return this.type;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(url, type);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      Console that = Console.class.cast(obj);
+      return Objects.equal(this.url, that.url)
+         && Objects.equal(this.type, that.type);
+   }
+
+   protected ToStringHelper string() {
+      return toStringHelper(this).add("url", url).add("type", type);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b259af48/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ConsolesApi.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ConsolesApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ConsolesApi.java
new file mode 100644
index 0000000..5f3c848
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ConsolesApi.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.openstack.nova.v2_0.extensions;
+
+import org.jclouds.openstack.nova.v2_0.domain.Console;
+import org.jclouds.openstack.v2_0.ServiceType;
+import org.jclouds.openstack.v2_0.services.Extension;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Provides synchronous access to Consoles.
+ * <p/>
+ *
+ * @see ConsoleAsyncApi
+ */
+@Beta
+@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.CONSOLES)
+public interface ConsolesApi {
+   /**
+    * Get the Console
+    * @param serverId Server id
+    * @param type see {@link Console.Type}
+    * @return a Console object containing the console url and type.
+    */
+   Console getConsole(String serverId, Console.Type type);
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b259af48/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ConsolesAsyncApi.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ConsolesAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ConsolesAsyncApi.java
new file mode 100644
index 0000000..97f2af7
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ConsolesAsyncApi.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.openstack.nova.v2_0.extensions;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.fallbacks.MapHttp4xxCodesToExceptions;
+import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.nova.v2_0.domain.Console;
+import org.jclouds.openstack.v2_0.ServiceType;
+import org.jclouds.openstack.nova.v2_0.binders.BindConsoleToJsonPayload;
+import org.jclouds.openstack.v2_0.services.Extension;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.annotations.PayloadParam;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.SelectJson;
+
+import com.google.common.annotations.Beta;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides asynchronous access to Consoles via the REST API.
+ * <p/>
+ *
+ * @see ConsoleApi
+ * @see ExtensionAsyncApi
+ */
+@Beta
+@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.CONSOLES)
+@RequestFilters(AuthenticateRequest.class)
+public interface ConsolesAsyncApi {
+   /**
+    * @see ConsolesApi#getConsole
+    */
+   @Named("server:console")
+   @POST
+   @Path("/servers/{serverId}/action")
+   @SelectJson("console")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Produces(MediaType.APPLICATION_JSON)
+   @Fallback(MapHttp4xxCodesToExceptions.class)
+   @MapBinder(BindConsoleToJsonPayload.class)
+   ListenableFuture<? extends Console> getConsole(@PathParam("serverId") String serverId,
+         @PayloadParam("type") Console.Type type);
+
+}
+

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b259af48/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ExtensionNamespaces.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ExtensionNamespaces.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ExtensionNamespaces.java
index 5e335f1..503f32e 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ExtensionNamespaces.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ExtensionNamespaces.java
@@ -105,4 +105,9 @@ public interface ExtensionNamespaces {
     * Aggregates extension
     */
    public static final String AGGREGATES = "http://docs.openstack.org/ext/aggregates/api/v1.1";
+
+   /**
+    * Consoles extension
+    */
+   public static final String CONSOLES = "http://docs.openstack.org/compute/ext/os-consoles/api/v2";
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b259af48/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ServerApi.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ServerApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ServerApi.java
index 59fd081..13f793a 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ServerApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ServerApi.java
@@ -269,7 +269,6 @@ public interface ServerApi {
     * @return A Map containing the collected values organized by key - value.
     * @Beta
     */
-    Optional<Map<String, String>> getDiagnostics(String id);
-
+   Optional<Map<String, String>> getDiagnostics(String id);
 
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b259af48/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/ConsolesApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/ConsolesApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/ConsolesApiLiveTest.java
new file mode 100644
index 0000000..c74dbad
--- /dev/null
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/ConsolesApiLiveTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.openstack.nova.v2_0.extensions;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.openstack.nova.v2_0.domain.Console;
+import org.jclouds.openstack.nova.v2_0.domain.Server;
+import org.jclouds.openstack.nova.v2_0.features.ServerApi;
+import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Optional;
+
+/**
+ * Tests behavior of {@code ConsolesApi}
+ */
+@Test(groups = "live", testName = "ConsolesApiLiveTest")
+public class ConsolesApiLiveTest extends BaseNovaApiLiveTest {
+
+   public void testGetNOVNCConsole() {
+      testGetConsole(Console.Type.NOVNC);
+   }
+
+   public void testGetXVPVNCConsole() {
+      testGetConsole(Console.Type.XVPVNC);
+   }
+
+   private void testGetConsole(Console.Type consoleType) {
+      for (String zoneId : api.getConfiguredZones()) {
+         Optional<? extends ConsolesApi> apiOption = api.getConsolesExtensionForZone(zoneId);
+         if (!apiOption.isPresent()) {
+            System.err.println("Consoles extension not present in server.");
+            continue;
+         }
+
+         ConsolesApi api = apiOption.get();
+         ServerApi serverApi = this.api.getServerApiForZone(zoneId);
+         Server server = createServerInZone(zoneId);
+         Console console = api.getConsole(server.getId(), consoleType);
+         assertNotNull(console.getType());
+         assertTrue(consoleType.equals(console.getType()));
+         assertNotNull(console.getUrl());
+         assertTrue(console.getUrl().toString().startsWith("http"));
+         serverApi.delete(server.getId());
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b259af48/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/ConsolesApiMockTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/ConsolesApiMockTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/ConsolesApiMockTest.java
new file mode 100644
index 0000000..6bd5244
--- /dev/null
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/ConsolesApiMockTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.openstack.nova.v2_0.extensions;
+
+import static com.google.common.collect.Iterables.getFirst;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.fail;
+
+import org.jclouds.openstack.nova.v2_0.NovaApi;
+import org.jclouds.openstack.nova.v2_0.domain.Console;
+import org.jclouds.openstack.nova.v2_0.parse.ParseNOVNCConsoleTest;
+import org.jclouds.openstack.nova.v2_0.parse.ParseRDPConsoleTest;
+import org.jclouds.openstack.nova.v2_0.parse.ParseSPICEConsoleTest;
+import org.jclouds.openstack.nova.v2_0.parse.ParseXVPVNCConsoleTest;
+import org.jclouds.openstack.v2_0.internal.BaseOpenStackMockTest;
+import org.testng.annotations.Test;
+
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+
+/**
+ * Tests ConsolesApi Guice wiring and parsing
+ */
+@Test(groups = "unit", testName = "ConsolesApiMockTest", enabled = false)
+public class ConsolesApiMockTest extends BaseOpenStackMockTest<NovaApi> {
+
+   public void testNullConsoleType() {
+      assertNull(Console.Type.fromValue(null));
+   }
+
+   public void testUnrecognizedConsoleType() {
+      assertEquals(Console.Type.UNRECOGNIZED, Console.Type.fromValue("invalid type"));
+   }
+
+   public void getNOVNCConsole() throws Exception {
+      getConsole(Console.Type.NOVNC, "/novnc_console.json", new ParseNOVNCConsoleTest().expected());
+   }
+
+   public void getNOVNCConsoleWhenResponseIs404NotFound() throws Exception {
+      getConsoleWhenResponseIs404NotFound(Console.Type.NOVNC);
+   }
+
+   public void getXVPVNCConsole() throws Exception {
+      getConsole(Console.Type.XVPVNC, "/xvpvnc_console.json", new ParseXVPVNCConsoleTest().expected());
+   }
+
+   public void getXVPVNCConsoleWhenResponseIs404NotFound() throws Exception {
+      getConsoleWhenResponseIs404NotFound(Console.Type.XVPVNC);
+   }
+
+   public void getSPICEConsole() throws Exception {
+      getConsole(Console.Type.SPICE_HTML5, "/spice_console.json", new ParseSPICEConsoleTest().expected());
+   }
+
+   public void getSPICEConsoleWhenResponseIs404NotFound() throws Exception {
+      getConsoleWhenResponseIs404NotFound(Console.Type.SPICE_HTML5);
+   }
+
+   public void getRDPConsole() throws Exception {
+      getConsole(Console.Type.RDP_HTML5, "/rdp_console.json", new ParseRDPConsoleTest().expected());
+   }
+
+   public void getRDPConsoleWhenResponseIs404NotFound() throws Exception {
+      getConsoleWhenResponseIs404NotFound(Console.Type.RDP_HTML5);
+   }
+
+   private void getConsole(Console.Type consoleType, String responseResource, Console expected) throws Exception {
+      String serverId = "5f64fca7-879b-4173-bf9c-8fa88330a4dc";
+
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/keystoneAuthResponse.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/extension_list_full.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource(responseResource))));
+
+      try {
+         NovaApi novaApi = api(server.getUrl("/").toString(), "openstack-nova");
+
+         String zoneId = getFirst(novaApi.getConfiguredZones(), "RegionTwo");
+
+         System.out.println("zoneId: " + zoneId);
+         ConsolesApi consolesApi = novaApi.getConsolesExtensionForZone(zoneId).get();
+
+         assertEquals(server.getRequestCount(), 2);
+         assertAuthentication(server);
+         assertEquals(server.takeRequest().getRequestLine(),
+                 "GET /v2/da0d12be20394afb851716e10a49e4a7/extensions HTTP/1.1");
+         assertEquals(consolesApi.getConsole(serverId, consoleType), expected);
+
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   private void getConsoleWhenResponseIs404NotFound(Console.Type consoleType) throws Exception {
+      String serverId = "5f64fca7-879b-4173-bf9c-8fa88330a4dc";
+
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/extension_list_full.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse()
+                  .setStatus("HTTP/1.1 404 Not Found")
+                  .setBody("{\"itemNotFound\":" + "{\"message\":\"Instance " + serverId
+                      + " could not be found.\",\"code\":404}}")
+                  .setHeader("Content-Type", "application/json; charset=UTF-8")));
+
+      try {
+         NovaApi novaApi = api(server.getUrl("/").toString(), "openstack-nova");
+
+         String zoneId = getFirst(novaApi.getConfiguredZones(), "RegionTwo");
+
+         ConsolesApi consolesApi = novaApi.getConsolesExtensionForZone(zoneId).get();
+
+         assertEquals(server.getRequestCount(), 2);
+         assertAuthentication(server);
+         assertEquals(server.takeRequest().getRequestLine(),
+                 "GET /v2/da0d12be20394afb851716e10a49e4a7/extensions HTTP/1.1");
+
+         try {
+             consolesApi.getConsole(serverId, consoleType);
+             fail("expected a ResourceNotFoundException");
+         } catch (org.jclouds.rest.ResourceNotFoundException e) {
+             // expected
+         }
+
+      } finally {
+         server.shutdown();
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b259af48/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseNOVNCConsoleTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseNOVNCConsoleTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseNOVNCConsoleTest.java
new file mode 100644
index 0000000..9f0d925
--- /dev/null
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseNOVNCConsoleTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.openstack.nova.v2_0.parse;
+
+import java.net.URI;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.json.BaseItemParserTest;
+import org.jclouds.json.config.GsonModule;
+import org.jclouds.openstack.nova.v2_0.config.NovaParserModule;
+import org.jclouds.openstack.nova.v2_0.domain.Console;
+import org.jclouds.rest.annotations.SelectJson;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Throwables;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+/**
+ * Tests parsing of vnc console response. 
+ */
+@Test(groups = "unit", testName = "ParseNOVNCConsoleTest")
+public class ParseNOVNCConsoleTest extends BaseItemParserTest<Console> {
+
+   @Override
+   public String resource() {
+      return "/novnc_console.json";
+   }
+
+   @Override
+   @SelectJson("console")
+   @Consumes(MediaType.APPLICATION_JSON)
+   public Console expected() {
+      Console console = null;
+      try {
+         console = Console
+            .builder()
+            .url(new URI("http://example.com:6080/vnc_auto.html?token=f9906a48-b71e-4f18"
+                     + "-baca-c987da3ebdb3&title=dafa(75ecef58-3b8e-4659-ab3b-5501454188e9)"))
+            .type(Console.Type.NOVNC)
+            .build();
+      } catch (Exception e) {
+         Throwables.propagate(e);
+      }
+
+      return console;
+   }
+
+   protected Injector injector() {
+      return Guice.createInjector(new NovaParserModule(), new GsonModule());
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b259af48/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseRDPConsoleTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseRDPConsoleTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseRDPConsoleTest.java
new file mode 100644
index 0000000..9c80a1c
--- /dev/null
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseRDPConsoleTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.openstack.nova.v2_0.parse;
+
+import java.net.URI;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.json.BaseItemParserTest;
+import org.jclouds.json.config.GsonModule;
+import org.jclouds.openstack.nova.v2_0.config.NovaParserModule;
+import org.jclouds.openstack.nova.v2_0.domain.Console;
+import org.jclouds.rest.annotations.SelectJson;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Throwables;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+/**
+ * Tests parsing of RDP console response.
+ */
+@Test(groups = "unit", testName = "ParseRDPConsoleTest")
+public class ParseRDPConsoleTest extends BaseItemParserTest<Console> {
+
+   @Override
+   public String resource() {
+      return "/rdp_console.json";
+   }
+
+   @Override
+   @SelectJson("console")
+   @Consumes(MediaType.APPLICATION_JSON)
+   public Console expected() {
+      Console console = null;
+
+      try {
+         console = Console
+            .builder()
+            .url(new URI("http://example.com:6083/?token=f9906a48-b71e-4f18-baca-"
+                     + "c987da3ebdb3&title=dafa(75ecef58-3b8e-4659-ab3b-5501454188e9)"))
+            .type(Console.Type.RDP_HTML5)
+            .build();
+      } catch (Exception e) {
+         Throwables.propagate(e);
+      }
+
+      return console;
+   }
+
+   protected Injector injector() {
+      return Guice.createInjector(new NovaParserModule(), new GsonModule());
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b259af48/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseSPICEConsoleTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseSPICEConsoleTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseSPICEConsoleTest.java
new file mode 100644
index 0000000..f8eb47f
--- /dev/null
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseSPICEConsoleTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.openstack.nova.v2_0.parse;
+
+import java.net.URI;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.json.BaseItemParserTest;
+import org.jclouds.json.config.GsonModule;
+import org.jclouds.openstack.nova.v2_0.config.NovaParserModule;
+import org.jclouds.openstack.nova.v2_0.domain.Console;
+import org.jclouds.rest.annotations.SelectJson;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Throwables;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+/**
+ * Tests parsing of spice console response.
+ */
+@Test(groups = "unit", testName = "ParseSPICEConsoleTest")
+public class ParseSPICEConsoleTest extends BaseItemParserTest<Console> {
+
+   @Override
+   public String resource() {
+      return "/spice_console.json";
+   }
+
+   @Override
+   @SelectJson("console")
+   @Consumes(MediaType.APPLICATION_JSON)
+   public Console expected() {
+      Console console = null;
+
+      try {
+         console = Console
+            .builder()
+            .url(new URI("http://example.com:6080/spice_auto.html?token=f9906a48-b71e"
+                     + "-4f18-baca-c987da3ebdb3&title=dafa(75ecef58-3b8e-4659-ab3b-5501454188e9)"))
+            .type(Console.Type.SPICE_HTML5)
+            .build();
+      } catch (Exception e) {
+         Throwables.propagate(e);
+      }
+
+      return console;
+   }
+
+   protected Injector injector() {
+      return Guice.createInjector(new NovaParserModule(), new GsonModule());
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b259af48/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseXVPVNCConsoleTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseXVPVNCConsoleTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseXVPVNCConsoleTest.java
new file mode 100644
index 0000000..5a38829
--- /dev/null
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseXVPVNCConsoleTest.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.openstack.nova.v2_0.parse;
+
+import java.net.URI;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.json.BaseItemParserTest;
+import org.jclouds.json.config.GsonModule;
+import org.jclouds.openstack.nova.v2_0.config.NovaParserModule;
+import org.jclouds.openstack.nova.v2_0.domain.Console;
+import org.jclouds.rest.annotations.SelectJson;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Throwables;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+/**
+ * Tests parsing of vnc console response. 
+ */
+@Test(groups = "unit", testName = "ParseXVPVNCConsoleTest")
+public class ParseXVPVNCConsoleTest extends BaseItemParserTest<Console> {
+
+   @Override
+   public String resource() {
+      return "/xvpvnc_console.json";
+   }
+
+   @Override
+   @SelectJson("console")
+   @Consumes(MediaType.APPLICATION_JSON)
+   public Console expected() {
+      Console console = null;
+      try {
+         console = Console
+            .builder()
+            .url(new URI("http://example.com:6081/console?token=2abbe0b2-dcf1-479d-8d58-88e82b477865"))
+            .type(Console.Type.XVPVNC)
+            .build();
+      } catch (Exception e) {
+         Throwables.propagate(e);
+      }
+
+      return console;
+   }
+
+   protected Injector injector() {
+      return Guice.createInjector(new NovaParserModule(), new GsonModule());
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b259af48/apis/openstack-nova/src/test/resources/novnc_console.json
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/resources/novnc_console.json b/apis/openstack-nova/src/test/resources/novnc_console.json
new file mode 100644
index 0000000..0d74bcf
--- /dev/null
+++ b/apis/openstack-nova/src/test/resources/novnc_console.json
@@ -0,0 +1,7 @@
+{
+    "console": {
+        "type": "novnc",
+        "url": "http://example.com:6080/vnc_auto.html?token=f9906a48-b71e-4f18-baca-c987da3ebdb3&title=dafa(75ecef58-3b8e-4659-ab3b-5501454188e9)"
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b259af48/apis/openstack-nova/src/test/resources/rdp_console.json
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/resources/rdp_console.json b/apis/openstack-nova/src/test/resources/rdp_console.json
new file mode 100644
index 0000000..6088d57
--- /dev/null
+++ b/apis/openstack-nova/src/test/resources/rdp_console.json
@@ -0,0 +1,7 @@
+{
+    "console": {
+        "type": "rdp-html5",
+        "url": "http://example.com:6083/?token=f9906a48-b71e-4f18-baca-c987da3ebdb3&title=dafa(75ecef58-3b8e-4659-ab3b-5501454188e9)"
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b259af48/apis/openstack-nova/src/test/resources/spice_console.json
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/resources/spice_console.json b/apis/openstack-nova/src/test/resources/spice_console.json
new file mode 100644
index 0000000..bc6f5f5
--- /dev/null
+++ b/apis/openstack-nova/src/test/resources/spice_console.json
@@ -0,0 +1,7 @@
+{
+    "console": {
+        "type": "spice-html5",
+        "url": "http://example.com:6080/spice_auto.html?token=f9906a48-b71e-4f18-baca-c987da3ebdb3&title=dafa(75ecef58-3b8e-4659-ab3b-5501454188e9)"
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/jclouds/blob/b259af48/apis/openstack-nova/src/test/resources/xvpvnc_console.json
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/resources/xvpvnc_console.json b/apis/openstack-nova/src/test/resources/xvpvnc_console.json
new file mode 100644
index 0000000..ddaf6cf
--- /dev/null
+++ b/apis/openstack-nova/src/test/resources/xvpvnc_console.json
@@ -0,0 +1,7 @@
+{
+    "console": {
+        "type": "xvpvnc",
+        "url": "http://example.com:6081/console?token=2abbe0b2-dcf1-479d-8d58-88e82b477865"
+    }
+}
+