Repository: jclouds-labs-openstack
Updated Branches:
  refs/heads/master a1d6725b0 -> 7c1b681b6


JCLOUDS-494: Change Glance EndpointParam parser to negotiate endpoint version


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

Branch: refs/heads/master
Commit: 7c1b681b6699025aa56e6b64c7da9c0136349b00
Parents: a1d6725
Author: jasdeep-hundal <[email protected]>
Authored: Tue Mar 11 17:25:36 2014 -0700
Committer: Andrew Phillips <[email protected]>
Committed: Wed Apr 2 18:32:22 2014 +0200

----------------------------------------------------------------------
 .../ZoneToEndpointNegotiateVersion.java         | 143 ++++++++++++++
 .../openstack/glance/v1_0/GlanceApi.java        |   6 +-
 .../v1_0/handlers/GlanceErrorHandler.java       |   7 +
 .../GlanceVersionNegotiationExpectTest.java     | 104 ++++++++++
 .../v1_0/features/ImageApiExpectTest.java       |  95 +++++----
 .../v1_0/handlers/GlanceErrorHandlerTest.java   |  42 +++-
 .../v1_0/internal/BaseGlanceExpectTest.java     |   9 +
 .../test/resources/glanceVersionResponse.json   |  44 +++++
 .../glanceVersionResponseSchemeMismatch.json    |  44 +++++
 ...glanceVersionResponseVersionUnavailable.json |  14 ++
 ...toneAuthResponseVersionedGlanceEndpoint.json | 194 +++++++++++++++++++
 11 files changed, 653 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/7c1b681b/openstack-glance/src/main/java/org/jclouds/openstack/glance/functions/ZoneToEndpointNegotiateVersion.java
----------------------------------------------------------------------
diff --git 
a/openstack-glance/src/main/java/org/jclouds/openstack/glance/functions/ZoneToEndpointNegotiateVersion.java
 
b/openstack-glance/src/main/java/org/jclouds/openstack/glance/functions/ZoneToEndpointNegotiateVersion.java
new file mode 100644
index 0000000..9f6e341
--- /dev/null
+++ 
b/openstack-glance/src/main/java/org/jclouds/openstack/glance/functions/ZoneToEndpointNegotiateVersion.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2014 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.glance.functions;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.regex.Pattern;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.json.Json;
+import org.jclouds.location.Zone;
+import org.jclouds.rest.annotations.ApiVersion;
+import org.jclouds.rest.HttpClient;
+import org.jclouds.util.Strings2;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Splitter;
+import com.google.common.base.Supplier;
+import com.google.common.base.Throwables;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.Iterables;
+
+/**
+ *
+ * @author Jasdeep Hundal
+ */
+@Singleton
+public class ZoneToEndpointNegotiateVersion implements Function<Object, URI> {
+
+   public static final String VERSION_NEGOTIATION_HEADER = 
"Is-Version-Negotiation-Request";
+
+   private static final Pattern versionRegex = 
Pattern.compile("v[0-9]+(\\.[0-9])?[0-9]*");
+
+   private static class VersionsJsonResponse{
+      public static class Version {
+         public static class Link {
+            public String href;
+            public String rel;
+         }
+         public String status;
+         public String id;
+         public List<Link> links;
+      }
+      public List<Version> versions;
+   }
+
+   private final Supplier<Map<String, Supplier<URI>>> zoneToEndpointSupplier;
+   private final String apiVersion;
+   private final LoadingCache<URI, URI> endpointCache;
+
+   @Inject
+   public ZoneToEndpointNegotiateVersion(@Zone Supplier<Map<String, 
Supplier<URI>>> zoneToEndpointSupplier,
+         @ApiVersion String rawApiVersionString, final HttpClient client, 
final Json json) {
+      this.zoneToEndpointSupplier = checkNotNull(zoneToEndpointSupplier, 
"zoneToEndpointSupplier");
+      if (!rawApiVersionString.startsWith("v")) {
+         this.apiVersion = "v" + rawApiVersionString;
+      } else {
+         this.apiVersion = rawApiVersionString;
+      }
+      this.endpointCache = CacheBuilder.newBuilder()
+         .build(
+            new CacheLoader<URI, URI>() {
+               public URI load(URI baseEndpointUri) {
+                  try {
+                     List<String> baseEndpointPathParts = 
Splitter.on('/').omitEmptyStrings().splitToList(baseEndpointUri.getPath());
+                     if (!baseEndpointPathParts.isEmpty()
+                           && 
versionRegex.matcher(baseEndpointPathParts.get(baseEndpointPathParts.size() - 
1)).matches()) {
+                        // Constructs a base URI Glance endpoint by stripping 
the version from the received URI
+                        baseEndpointUri = new URI(baseEndpointUri.getScheme(), 
baseEndpointUri.getUserInfo(),
+                           baseEndpointUri.getHost(), 
baseEndpointUri.getPort(),
+                           
Joiner.on('/').join(baseEndpointPathParts.subList(0, 
baseEndpointPathParts.size() - 1)) + "/",
+                           baseEndpointUri.getQuery(), 
baseEndpointUri.getFragment());
+                     }
+
+                     HttpRequest negotiationRequest = HttpRequest.builder()
+                        .method("GET").endpoint(baseEndpointUri)
+                        .addHeader(VERSION_NEGOTIATION_HEADER, "true").build();
+                     InputStream response = 
client.invoke(negotiationRequest).getPayload().openStream();
+                     VersionsJsonResponse versions = 
json.fromJson(Strings2.toStringAndClose(response), VersionsJsonResponse.class);
+                     for (VersionsJsonResponse.Version version : 
versions.versions) {
+                        if (apiVersion.equals(version.id)) {
+                           // We only expect one element here, we'll get an 
exception here if that changes
+                           URI versionedEndpointUri = new 
URI(Iterables.getOnlyElement(version.links).href);
+                           return new URI(baseEndpointUri.getScheme(), 
versionedEndpointUri.getUserInfo(),
+                              versionedEndpointUri.getHost(), 
versionedEndpointUri.getPort(),
+                              versionedEndpointUri.getPath(), 
versionedEndpointUri.getQuery(),
+                              versionedEndpointUri.getFragment());
+                        }
+                     }
+                  } catch (URISyntaxException ex) {
+                     throw Throwables.propagate(ex);
+                  } catch (IOException ex) {
+                     throw Throwables.propagate(ex);
+                  }
+                  throw new UnsupportedOperationException("Glance endpoint 
does not support API version: " + apiVersion);
+              }
+         });
+   }
+
+   @Override
+   public URI apply(Object from) {
+      checkArgument(from instanceof String, "you must specify a zone, as a 
String argument");
+      Map<String, Supplier<URI>> zoneToEndpoint = zoneToEndpointSupplier.get();
+      checkState(!zoneToEndpoint.isEmpty(), "no zone name to endpoint mappings 
configured!");
+      checkArgument(zoneToEndpoint.containsKey(from),
+               "requested location %s, which is not in the configured 
locations: %s", from, zoneToEndpoint);
+      URI uri = zoneToEndpointSupplier.get().get(from).get();
+
+      try {
+         return endpointCache.get(uri);
+      } catch (ExecutionException ex) {
+         throw Throwables.propagate(ex);
+      }
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/7c1b681b/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/GlanceApi.java
----------------------------------------------------------------------
diff --git 
a/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/GlanceApi.java
 
b/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/GlanceApi.java
index 7c16f41..c962eec 100644
--- 
a/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/GlanceApi.java
+++ 
b/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/GlanceApi.java
@@ -21,7 +21,7 @@ import java.util.Set;
 
 import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.location.Zone;
-import org.jclouds.location.functions.ZoneToEndpoint;
+import org.jclouds.openstack.glance.functions.ZoneToEndpointNegotiateVersion;
 import org.jclouds.openstack.glance.v1_0.features.ImageApi;
 import org.jclouds.openstack.v2_0.features.ExtensionApi;
 import org.jclouds.rest.annotations.Delegate;
@@ -50,12 +50,12 @@ public interface GlanceApi extends Closeable {
     */
    @Delegate
    ExtensionApi getExtensionApiForZone(
-         @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
+         @EndpointParam(parser = ZoneToEndpointNegotiateVersion.class) 
@Nullable String zone);
 
    /**
     * Provides access to Image features.
     */
    @Delegate
-   ImageApi getImageApiForZone(@EndpointParam(parser = ZoneToEndpoint.class) 
@Nullable String zone);
+   ImageApi getImageApiForZone(@EndpointParam(parser = 
ZoneToEndpointNegotiateVersion.class) @Nullable String zone);
 
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/7c1b681b/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/handlers/GlanceErrorHandler.java
----------------------------------------------------------------------
diff --git 
a/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/handlers/GlanceErrorHandler.java
 
b/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/handlers/GlanceErrorHandler.java
index aaff9bf..3659dda 100644
--- 
a/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/handlers/GlanceErrorHandler.java
+++ 
b/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/handlers/GlanceErrorHandler.java
@@ -24,6 +24,7 @@ import org.jclouds.http.HttpCommand;
 import org.jclouds.http.HttpErrorHandler;
 import org.jclouds.http.HttpResponse;
 import org.jclouds.http.HttpResponseException;
+import org.jclouds.openstack.glance.functions.ZoneToEndpointNegotiateVersion;
 import org.jclouds.rest.AuthorizationException;
 import org.jclouds.rest.ResourceNotFoundException;
 
@@ -46,6 +47,12 @@ public class GlanceErrorHandler implements HttpErrorHandler {
       message = message != null ? message : String.format("%s -> %s", 
command.getCurrentRequest().getRequestLine(),
                response.getStatusLine());
       switch (response.getStatusCode()) {
+         // do not throw exceptions on Glance version negotiation
+         case 300:
+            if 
(command.getCurrentRequest().getFirstHeaderOrNull(ZoneToEndpointNegotiateVersion.VERSION_NEGOTIATION_HEADER)
 != null) {
+               return;
+            }
+            break;
          case 400:
             break;
          case 401:

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/7c1b681b/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/features/GlanceVersionNegotiationExpectTest.java
----------------------------------------------------------------------
diff --git 
a/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/features/GlanceVersionNegotiationExpectTest.java
 
b/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/features/GlanceVersionNegotiationExpectTest.java
new file mode 100644
index 0000000..5f8062e
--- /dev/null
+++ 
b/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/features/GlanceVersionNegotiationExpectTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.glance.v1_0.features;
+
+import static org.testng.Assert.assertEquals;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.glance.v1_0.GlanceApi;
+import org.jclouds.openstack.glance.v1_0.internal.BaseGlanceApiExpectTest;
+import org.jclouds.openstack.glance.v1_0.parse.ParseImagesTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Jasdeep Hundal
+ */
+@Test(groups = "unit", testName = "GlanceVersionNegotiationExpectTest")
+public class GlanceVersionNegotiationExpectTest extends 
BaseGlanceApiExpectTest {
+
+    /*
+     * Test that if Glance returns a URL for a version with a different scheme
+     * than we used for the base endpoint we use the scheme associated w/ the
+     * base endpoint.
+     *
+     * This is useful for when Glance is behind a proxy.
+     */
+   public void testSchemeMismatch() throws Exception {
+      // The referenced resource contains http endpoints for versions instead 
of the https endpoint returned by Keystone
+      versionNegotiationResponse = 
HttpResponse.builder().statusCode(300).message("HTTP/1.1 300 Multiple 
Choices").payload(
+            
payloadFromResourceWithContentType("/glanceVersionResponseSchemeMismatch.json", 
"application/json")).build();
+
+      HttpRequest list = HttpRequest.builder().method("GET")
+            .endpoint("https://glance.jclouds.org:9292/v1.0/images";)
+            .addHeader("Accept", "application/json")
+            .addHeader("X-Auth-Token", authToken).build();
+
+
+      HttpResponse listResponse = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/images.json")).build();
+
+      GlanceApi apiWhenExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            list, listResponse);
+
+      
assertEquals(apiWhenExist.getImageApiForZone("az-1.region-a.geo-1").list().concat().toString(),
+            new ParseImagesTest().expected().toString());
+   }
+
+    /*
+     * Test that Glance version negotiation fails with an exception if there is
+     * no endpoint returned for the requested version.
+     */
+   @Test(expectedExceptions = UnsupportedOperationException.class)
+   public void testNonExistentVersion() throws Exception {
+      // The referenced resource only an endpoint for v999.999 of the GlanceApi
+      HttpResponse localVersionNegotiationResponse = 
HttpResponse.builder().statusCode(300).message("HTTP/1.1 300 Multiple 
Choices").payload(
+            
payloadFromResourceWithContentType("/glanceVersionResponseVersionUnavailable.json",
 "application/json")).build();
+
+      GlanceApi apiWhenExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
+            responseWithKeystoneAccess, versionNegotiationRequest, 
localVersionNegotiationResponse);
+
+      apiWhenExist.getImageApiForZone("az-1.region-a.geo-1").list();
+   }
+
+    /*
+     * Test that Glance version negotiation happens with the base endpoint if
+     * the Keystone catalog returns an already versioned endpoint for Glance
+     */
+   public void testKeystoneReturnsVersionedEndpoint() throws Exception {
+      // This sets the keystone response to return a Glance endpoint w/ 
version already present
+      HttpResponse localResponseWithKeystoneAccess = 
HttpResponse.builder().statusCode(200).message("HTTP/1.1 200").payload(
+            
payloadFromResourceWithContentType("/keystoneAuthResponseVersionedGlanceEndpoint.json",
 "application/json")).build();
+
+      HttpRequest list = HttpRequest.builder().method("GET")
+            .endpoint("https://glance.jclouds.org:9292/v1.0/images";)
+            .addHeader("Accept", "application/json")
+            .addHeader("X-Auth-Token", authToken).build();
+
+
+      HttpResponse listResponse = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/images.json")).build();
+
+      GlanceApi apiWhenExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
+            localResponseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            list, listResponse);
+
+      
assertEquals(apiWhenExist.getImageApiForZone("az-1.region-a.geo-1").list().concat().toString(),
+            new ParseImagesTest().expected().toString());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/7c1b681b/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/features/ImageApiExpectTest.java
----------------------------------------------------------------------
diff --git 
a/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/features/ImageApiExpectTest.java
 
b/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/features/ImageApiExpectTest.java
index 9b4e053..d200422 100644
--- 
a/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/features/ImageApiExpectTest.java
+++ 
b/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/features/ImageApiExpectTest.java
@@ -51,7 +51,7 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
 
    public void testListWhenResponseIs2xx() throws Exception {
       HttpRequest list = HttpRequest.builder().method("GET")
-            .endpoint("https://glance.jclouds.org:9292/images";)
+            .endpoint("https://glance.jclouds.org:9292/v1.0/images";)
             .addHeader("Accept", "application/json")
             .addHeader("X-Auth-Token", authToken).build();
 
@@ -60,7 +60,8 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
             .payload(payloadFromResource("/images.json")).build();
 
       GlanceApi apiWhenExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, list, listResponse);
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            list, listResponse);
 
       assertEquals(apiWhenExist.getConfiguredZones(), 
ImmutableSet.of("az-1.region-a.geo-1"));
 
@@ -70,21 +71,22 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
 
    public void testListWhenReponseIs404IsEmpty() throws Exception {
       HttpRequest list = HttpRequest.builder().method("GET")
-            .endpoint("https://glance.jclouds.org:9292/images";)
+            .endpoint("https://glance.jclouds.org:9292/v1.0/images";)
             .addHeader("Accept", "application/json")
             .addHeader("X-Auth-Token", authToken).build();
 
       HttpResponse listResponse = 
HttpResponse.builder().statusCode(404).build();
 
       GlanceApi apiWhenNoExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, list, listResponse);
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            list, listResponse);
 
       
assertTrue(apiWhenNoExist.getImageApiForZone("az-1.region-a.geo-1").list().concat().isEmpty());
    }
 
    public void testListInDetailWhenResponseIs2xx() throws Exception {
       HttpRequest listInDetail = HttpRequest.builder().method("GET")
-            .endpoint("https://glance.jclouds.org:9292/images/detail";)
+            .endpoint("https://glance.jclouds.org:9292/v1.0/images/detail";)
             .addHeader("Accept", "application/json")
             .addHeader("X-Auth-Token", authToken).build();
 
@@ -93,7 +95,8 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
             .payload(payloadFromResource("/images_detail.json")).build();
 
       GlanceApi apiWhenExistInDetail = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, listInDetail, listInDetailResponse);
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            listInDetail, listInDetailResponse);
 
       assertEquals(apiWhenExistInDetail.getConfiguredZones(), 
ImmutableSet.of("az-1.region-a.geo-1"));
 
@@ -103,7 +106,7 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
 
    public void testListInDetailWhenReponseIs404IsEmpty() throws Exception {
       HttpRequest listInDetail = HttpRequest.builder().method("GET")
-            .endpoint("https://glance.jclouds.org:9292/images/detail";)
+            .endpoint("https://glance.jclouds.org:9292/v1.0/images/detail";)
             .addHeader("Accept", "application/json")
             .addHeader("X-Auth-Token", authToken).build();
 
@@ -111,7 +114,8 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
       HttpResponse listInDetailResponse = 
HttpResponse.builder().statusCode(404).build();
 
       GlanceApi apiWhenNoExistInDetail = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, listInDetail, listInDetailResponse);
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            listInDetail, listInDetailResponse);
 
       
assertTrue(apiWhenNoExistInDetail.getImageApiForZone("az-1.region-a.geo-1").listInDetail().concat().isEmpty());
    }
@@ -120,14 +124,15 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
       HttpRequest show = HttpRequest
             .builder()
             .method("HEAD")
-            
.endpoint("https://glance.jclouds.org:9292/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
+            
.endpoint("https://glance.jclouds.org:9292/v1.0/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
             .addHeader("X-Auth-Token", authToken).build();
 
 
       HttpResponse showResponse = new 
ParseImageDetailsFromHeadersTest().response;
 
       GlanceApi apiWhenExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, show, showResponse);
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            show, showResponse);
 
       assertEquals(apiWhenExist.getConfiguredZones(), 
ImmutableSet.of("az-1.region-a.geo-1"));
 
@@ -137,14 +142,15 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
 
    public void testShowWhenReponseIs404IsNull() throws Exception {
       HttpRequest show = HttpRequest.builder().method("HEAD")
-            
.endpoint("https://glance.jclouds.org:9292/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
+            
.endpoint("https://glance.jclouds.org:9292/v1.0/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
             .addHeader("X-Auth-Token", authToken).build();
 
 
       HttpResponse showResponse = 
HttpResponse.builder().statusCode(404).build();
 
       GlanceApi apiWhenNoExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, show, showResponse);
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            show, showResponse);
 
       
assertNull(apiWhenNoExist.getImageApiForZone("az-1.region-a.geo-1").get("fcc451d0-f6e4-4824-ad8f-70ec12326d07"));
    }
@@ -152,14 +158,15 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
 
    public void testGetAsStreamWhenResponseIs2xx() throws Exception {
       HttpRequest get = HttpRequest.builder().method("GET")
-            
.endpoint("https://glance.jclouds.org:9292/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
+            
.endpoint("https://glance.jclouds.org:9292/v1.0/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
             .addHeader("X-Auth-Token", authToken).build();
 
 
       HttpResponse getResponse = 
HttpResponse.builder().statusCode(200).payload(Payloads.newStringPayload("foo")).build();
       
       GlanceApi apiWhenExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, get, getResponse);
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            get, getResponse);
 
       assertEquals(apiWhenExist.getConfiguredZones(), 
ImmutableSet.of("az-1.region-a.geo-1"));
 
@@ -169,21 +176,22 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
 
    public void testGetAsStreamWhenReponseIs404IsNull() throws Exception {
       HttpRequest get = HttpRequest.builder().method("GET")
-            
.endpoint("https://glance.jclouds.org:9292/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
+            
.endpoint("https://glance.jclouds.org:9292/v1.0/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
             .addHeader("X-Auth-Token", authToken).build();
 
 
       HttpResponse getResponse = 
HttpResponse.builder().statusCode(404).build();
 
       GlanceApi apiWhenNoExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, get, getResponse);
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            get, getResponse);
 
       
assertNull(apiWhenNoExist.getImageApiForZone("az-1.region-a.geo-1").getAsStream("fcc451d0-f6e4-4824-ad8f-70ec12326d07"));
    }
 
    public void testCreateWhenResponseIs2xx() throws Exception {
       HttpRequest get = HttpRequest.builder().method("POST")
-            .endpoint("https://glance.jclouds.org:9292/images";)
+            .endpoint("https://glance.jclouds.org:9292/v1.0/images";)
             .addHeader("x-image-meta-name", "test")
             .addHeader("Accept", MediaType.APPLICATION_JSON)
             .addHeader("X-Auth-Token", authToken)
@@ -193,7 +201,8 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
             .payload(payloadFromResource("/image.json")).build();
       
       GlanceApi apiWhenExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, get, createResponse);
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            get, createResponse);
 
       assertEquals(apiWhenExist.getConfiguredZones(), 
ImmutableSet.of("az-1.region-a.geo-1"));
 
@@ -204,7 +213,7 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
    @Test(expectedExceptions = AuthorizationException.class)
    public void testCreateWhenResponseIs4xx() throws Exception {
       HttpRequest get = HttpRequest.builder().method("POST")
-            .endpoint("https://glance.jclouds.org:9292/images";)
+            .endpoint("https://glance.jclouds.org:9292/v1.0/images";)
             .addHeader("x-image-meta-name", "test")
             .addHeader("Accept", MediaType.APPLICATION_JSON)
             .addHeader("X-Auth-Token", authToken)
@@ -214,7 +223,8 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
             .payload(payloadFromResource("/image.json")).build();
 
       GlanceApi apiWhenExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, get, createResponse);
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            get, createResponse);
 
       assertEquals(apiWhenExist.getConfiguredZones(), 
ImmutableSet.of("az-1.region-a.geo-1"));
 
@@ -223,7 +233,7 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
 
    public void testReserveWhenResponseIs2xx() throws Exception {
       HttpRequest get = HttpRequest.builder().method("POST")
-            .endpoint("https://glance.jclouds.org:9292/images";)
+            .endpoint("https://glance.jclouds.org:9292/v1.0/images";)
             .addHeader("x-image-meta-name", "test")
             .addHeader("Accept", MediaType.APPLICATION_JSON)
             .addHeader("X-Auth-Token", authToken).build();
@@ -232,7 +242,8 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
             .payload(payloadFromResource("/image.json")).build();
 
       GlanceApi apiWhenExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, get, createResponse);
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            get, createResponse);
 
       assertEquals(apiWhenExist.getConfiguredZones(), 
ImmutableSet.of("az-1.region-a.geo-1"));
 
@@ -242,7 +253,7 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
    @Test(expectedExceptions = AuthorizationException.class)
    public void testReserveWhenResponseIs4xx() throws Exception {
       HttpRequest get = HttpRequest.builder().method("POST")
-            .endpoint("https://glance.jclouds.org:9292/images";)
+            .endpoint("https://glance.jclouds.org:9292/v1.0/images";)
             .addHeader("x-image-meta-name", "test")
             .addHeader("Accept", MediaType.APPLICATION_JSON)
             .addHeader("X-Auth-Token", authToken).build();
@@ -251,7 +262,8 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
             .payload(payloadFromResource("/image.json")).build();
 
       GlanceApi apiWhenExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, get, createResponse);
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            get, createResponse);
 
       assertEquals(apiWhenExist.getConfiguredZones(), 
ImmutableSet.of("az-1.region-a.geo-1"));
 
@@ -260,7 +272,7 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
    
    public void testUpdateMetadataWhenResponseIs2xx() throws Exception {
       HttpRequest get = HttpRequest.builder().method("PUT")
-            
.endpoint("https://glance.jclouds.org:9292/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
+            
.endpoint("https://glance.jclouds.org:9292/v1.0/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
             .headers(
                   ImmutableMultimap.<String, String>builder()
                         .put("Accept", MediaType.APPLICATION_JSON)
@@ -278,7 +290,8 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
             .payload(payloadFromResource("/image.json")).build();
 
       GlanceApi apiWhenExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, get, updateResponse);
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            get, updateResponse);
 
       assertEquals(apiWhenExist.getConfiguredZones(), 
ImmutableSet.of("az-1.region-a.geo-1"));
 
@@ -297,7 +310,7 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
    @Test(expectedExceptions = ResourceNotFoundException.class)
    public void testUpdateMetadataWhenResponseIs4xx() throws Exception {
       HttpRequest get = HttpRequest.builder().method("PUT")
-            
.endpoint("https://glance.jclouds.org:9292/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
+            
.endpoint("https://glance.jclouds.org:9292/v1.0/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
             .headers(
                   ImmutableMultimap.<String, String>builder()
                         .put("Accept", MediaType.APPLICATION_JSON)
@@ -309,7 +322,8 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
       HttpResponse updateResponse = 
HttpResponse.builder().statusCode(404).build();
 
       GlanceApi apiWhenExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, get, updateResponse);
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            get, updateResponse);
 
       assertEquals(apiWhenExist.getConfiguredZones(), 
ImmutableSet.of("az-1.region-a.geo-1"));
 
@@ -321,7 +335,7 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
 
    public void testUpdateImageWhenResponseIs2xx() throws Exception {
       HttpRequest get = HttpRequest.builder().method("PUT")
-            
.endpoint("https://glance.jclouds.org:9292/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
+            
.endpoint("https://glance.jclouds.org:9292/v1.0/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
             .addHeader("Accept", MediaType.APPLICATION_JSON)
             .addHeader("X-Auth-Token", authToken)
             .payload(payloadFromStringWithContentType("somenewdata", 
MediaType.APPLICATION_OCTET_STREAM))
@@ -332,7 +346,8 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
 
 
       GlanceApi apiWhenExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, get, updateResponse);
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            get, updateResponse);
 
       assertEquals(apiWhenExist.getConfiguredZones(), 
ImmutableSet.of("az-1.region-a.geo-1"));
 
@@ -342,7 +357,7 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
 
    public void testUpdateNameAndImageWhenResponseIs2xx() throws Exception {
       HttpRequest get = HttpRequest.builder().method("PUT")
-            
.endpoint("https://glance.jclouds.org:9292/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
+            
.endpoint("https://glance.jclouds.org:9292/v1.0/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
             .headers(
                   ImmutableMultimap.<String, String>builder()
                         .put("Accept", MediaType.APPLICATION_JSON)
@@ -356,7 +371,8 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
 
 
       GlanceApi apiWhenExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, get, updateResponse);
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            get, updateResponse);
 
       assertEquals(apiWhenExist.getConfiguredZones(), 
ImmutableSet.of("az-1.region-a.geo-1"));
 
@@ -367,7 +383,7 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
    @Test(expectedExceptions = AuthorizationException.class)
    public void testUpdateNameAndImageWhenResponseIs4xx() throws Exception {
       HttpRequest get = HttpRequest.builder().method("PUT")
-            
.endpoint("https://glance.jclouds.org:9292/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
+            
.endpoint("https://glance.jclouds.org:9292/v1.0/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
             .headers(
                   ImmutableMultimap.<String, String>builder()
                         .put("Accept", MediaType.APPLICATION_JSON)
@@ -379,7 +395,8 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
       HttpResponse updateResponse = 
HttpResponse.builder().statusCode(403).build();
 
       GlanceApi apiWhenExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, get, updateResponse);
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            get, updateResponse);
 
       assertEquals(apiWhenExist.getConfiguredZones(), 
ImmutableSet.of("az-1.region-a.geo-1"));
 
@@ -389,13 +406,14 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
 
    public void testDeleteWhenResponseIs2xx() throws Exception {
       HttpRequest get = HttpRequest.builder().method("DELETE")
-            
.endpoint("https://glance.jclouds.org:9292/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
+            
.endpoint("https://glance.jclouds.org:9292/v1.0/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
             .addHeader("X-Auth-Token", authToken).build();
 
       HttpResponse getResponse = 
HttpResponse.builder().statusCode(200).build();
 
       GlanceApi apiWhenExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, get, getResponse);
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            get, getResponse);
 
       assertEquals(apiWhenExist.getConfiguredZones(), 
ImmutableSet.of("az-1.region-a.geo-1"));
 
@@ -404,14 +422,15 @@ public class ImageApiExpectTest extends 
BaseGlanceApiExpectTest {
 
    public void testDeleteWhenResponseIs4xx() throws Exception {
       HttpRequest get = HttpRequest.builder().method("DELETE")
-            
.endpoint("https://glance.jclouds.org:9292/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
+            
.endpoint("https://glance.jclouds.org:9292/v1.0/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07";)
             .addHeader("X-Auth-Token", authToken).build();
 
 
       HttpResponse getResponse = 
HttpResponse.builder().statusCode(404).build();
 
       GlanceApi apiWhenExist = 
requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, get, getResponse);
+            responseWithKeystoneAccess, versionNegotiationRequest, 
versionNegotiationResponse,
+            get, getResponse);
 
       assertEquals(apiWhenExist.getConfiguredZones(), 
ImmutableSet.of("az-1.region-a.geo-1"));
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/7c1b681b/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/handlers/GlanceErrorHandlerTest.java
----------------------------------------------------------------------
diff --git 
a/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/handlers/GlanceErrorHandlerTest.java
 
b/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/handlers/GlanceErrorHandlerTest.java
index 1245788..3c54ed7 100644
--- 
a/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/handlers/GlanceErrorHandlerTest.java
+++ 
b/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/handlers/GlanceErrorHandlerTest.java
@@ -16,45 +16,71 @@
  */
 package org.jclouds.openstack.glance.v1_0.handlers;
 
-import static org.easymock.EasyMock.createMockBuilder;
+import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.reportMatcher;
 import static org.easymock.EasyMock.verify;
 
 import java.net.URI;
+import java.util.Collections;
 
 import org.easymock.IArgumentMatcher;
 import org.jclouds.http.HttpCommand;
 import org.jclouds.http.HttpRequest;
 import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+
 /**
  * 
  * @author Adrian Cole
+ * @author Jasdeep Hundal
  */
 @Test(groups = "unit", testName = "GlanceErrorHandlerTest")
 public class GlanceErrorHandlerTest {
 
+   @Test
+   public void test300UnintendedVersionNegotiation() {
+      assertCodeMakes("GET", URI
+         .create("https://glance.jclouds.org:9292/";),
+         300, "Multiple Choices", "", HttpResponseException.class);
+   }
+
+   @Test
+   public void test300VersionNegotiation() {
+      assertCodeMakes("GET", 
Multimaps.forMap(Collections.singletonMap("Is-Version-Negotiation-Request", 
"true")),
+         URI.create("https://glance.jclouds.org:9292/";),
+         300, "Multiple Choices", "", null);
+   }
+
+   private void assertCodeMakes(String method, URI uri, int statusCode,
+            String message, String content, Class<? extends Exception> 
expected) {
+      assertCodeMakes(method, Multimaps.forMap(Collections.EMPTY_MAP), uri, 
statusCode, message, "text/plain", content, expected);
+   }
 
-   private void assertCodeMakes(String method, URI uri, int statusCode, String 
message, String content,
-            Class<? extends Exception> expected) {
-      assertCodeMakes(method, uri, statusCode, message, "text/plain", content, 
expected);
+   private void assertCodeMakes(String method, Multimap<String, String> 
headers, URI uri, int statusCode,
+            String message, String content, Class<? extends Exception> 
expected) {
+      assertCodeMakes(method, headers, uri, statusCode, message, "text/plain", 
content, expected);
    }
 
-   private void assertCodeMakes(String method, URI uri, int statusCode, String 
message, String contentType,
+   private void assertCodeMakes(String method, Multimap<String, String> 
headers, URI uri, int statusCode, String message, String contentType,
             String content, Class<? extends Exception> expected) {
 
       GlanceErrorHandler function = new GlanceErrorHandler();
 
-      HttpCommand command = createMockBuilder(HttpCommand.class).createMock();
-      HttpRequest request = 
HttpRequest.builder().method(method).endpoint(uri).build();
+      HttpCommand command = createMock(HttpCommand.class);
+      HttpRequest request = 
HttpRequest.builder().method(method).headers(headers).endpoint(uri).build();
       HttpResponse response = 
HttpResponse.builder().statusCode(statusCode).message(message).payload(content).build();
       response.getPayload().getContentMetadata().setContentType(contentType);
 
       expect(command.getCurrentRequest()).andReturn(request).atLeastOnce();
-      command.setException(classEq(expected));
+      if (expected != null) {
+         command.setException(classEq(expected));
+      }
 
       replay(command);
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/7c1b681b/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/internal/BaseGlanceExpectTest.java
----------------------------------------------------------------------
diff --git 
a/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/internal/BaseGlanceExpectTest.java
 
b/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/internal/BaseGlanceExpectTest.java
index 40dc393..6267b43 100644
--- 
a/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/internal/BaseGlanceExpectTest.java
+++ 
b/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/internal/BaseGlanceExpectTest.java
@@ -18,6 +18,7 @@ package org.jclouds.openstack.glance.v1_0.internal;
 
 import org.jclouds.http.HttpRequest;
 import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.glance.functions.ZoneToEndpointNegotiateVersion;
 import org.jclouds.openstack.keystone.v2_0.internal.KeystoneFixture;
 import org.jclouds.rest.internal.BaseRestApiExpectTest;
 
@@ -31,6 +32,8 @@ public class BaseGlanceExpectTest<T> extends 
BaseRestApiExpectTest<T> {
    protected HttpRequest keystoneAuthWithAccessKeyAndSecretKey;
    protected String authToken;
    protected HttpResponse responseWithKeystoneAccess;
+   protected HttpRequest versionNegotiationRequest;
+   protected HttpResponse versionNegotiationResponse;
    protected HttpRequest extensionsOfGlanceRequest;
    protected HttpResponse extensionsOfGlanceResponse;
    protected HttpResponse unmatchedExtensionsOfGlanceResponse;
@@ -46,5 +49,11 @@ public class BaseGlanceExpectTest<T> extends 
BaseRestApiExpectTest<T> {
       responseWithKeystoneAccess = 
KeystoneFixture.INSTANCE.responseWithAccess();
       // now, createContext arg will need tenant prefix
       identity = KeystoneFixture.INSTANCE.getTenantName() + ":" + identity;
+      // version negotiation
+      versionNegotiationRequest = HttpRequest.builder().method("GET")
+            .endpoint("https://glance.jclouds.org:9292/";)
+            
.addHeader(ZoneToEndpointNegotiateVersion.VERSION_NEGOTIATION_HEADER, 
"true").build();
+      versionNegotiationResponse = 
HttpResponse.builder().statusCode(300).message("HTTP/1.1 300 Multiple 
Choices").payload(
+            payloadFromResourceWithContentType("/glanceVersionResponse.json", 
"application/json")).build();
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/7c1b681b/openstack-glance/src/test/resources/glanceVersionResponse.json
----------------------------------------------------------------------
diff --git a/openstack-glance/src/test/resources/glanceVersionResponse.json 
b/openstack-glance/src/test/resources/glanceVersionResponse.json
new file mode 100644
index 0000000..fa34f63
--- /dev/null
+++ b/openstack-glance/src/test/resources/glanceVersionResponse.json
@@ -0,0 +1,44 @@
+{
+   "versions":[
+      {
+         "status":"CURRENT",
+         "id":"v2.1",
+         "links":[
+            {
+               "href":"https://glance.jclouds.org:9292/v2.0/";,
+               "rel":"self"
+            }
+         ]
+      },
+      {
+         "status":"SUPPORTED",
+         "id":"v2.0",
+         "links":[
+            {
+               "href":"https://glance.jclouds.org:9292/v2.0/";,
+               "rel":"self"
+            }
+         ]
+      },
+      {
+         "status":"CURRENT",
+         "id":"v1.1",
+         "links":[
+            {
+               "href":"https://glance.jclouds.org:9292/v1.0/";,
+               "rel":"self"
+            }
+         ]
+      },
+      {
+         "status":"SUPPORTED",
+         "id":"v1.0",
+         "links":[
+            {
+               "href":"https://glance.jclouds.org:9292/v1.0/";,
+               "rel":"self"
+            }
+         ]
+      }
+   ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/7c1b681b/openstack-glance/src/test/resources/glanceVersionResponseSchemeMismatch.json
----------------------------------------------------------------------
diff --git 
a/openstack-glance/src/test/resources/glanceVersionResponseSchemeMismatch.json 
b/openstack-glance/src/test/resources/glanceVersionResponseSchemeMismatch.json
new file mode 100644
index 0000000..bf17274
--- /dev/null
+++ 
b/openstack-glance/src/test/resources/glanceVersionResponseSchemeMismatch.json
@@ -0,0 +1,44 @@
+{
+   "versions":[
+      {
+         "status":"CURRENT",
+         "id":"v2.1",
+         "links":[
+            {
+               "href":"http://glance.jclouds.org:9292/v2.0/";,
+               "rel":"self"
+            }
+         ]
+      },
+      {
+         "status":"SUPPORTED",
+         "id":"v2.0",
+         "links":[
+            {
+               "href":"http://glance.jclouds.org:9292/v2.0/";,
+               "rel":"self"
+            }
+         ]
+      },
+      {
+         "status":"CURRENT",
+         "id":"v1.1",
+         "links":[
+            {
+               "href":"http://glance.jclouds.org:9292/v1.0/";,
+               "rel":"self"
+            }
+         ]
+      },
+      {
+         "status":"SUPPORTED",
+         "id":"v1.0",
+         "links":[
+            {
+               "href":"http://glance.jclouds.org:9292/v1.0/";,
+               "rel":"self"
+            }
+         ]
+      }
+   ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/7c1b681b/openstack-glance/src/test/resources/glanceVersionResponseVersionUnavailable.json
----------------------------------------------------------------------
diff --git 
a/openstack-glance/src/test/resources/glanceVersionResponseVersionUnavailable.json
 
b/openstack-glance/src/test/resources/glanceVersionResponseVersionUnavailable.json
new file mode 100644
index 0000000..bdc0b14
--- /dev/null
+++ 
b/openstack-glance/src/test/resources/glanceVersionResponseVersionUnavailable.json
@@ -0,0 +1,14 @@
+{
+   "versions":[
+      {
+         "status":"CURRENT",
+         "id":"v999.999",
+         "links":[
+            {
+               "href":"https://glance.jclouds.org:9292/v999.999/";,
+               "rel":"self"
+            }
+         ]
+      },
+   ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/7c1b681b/openstack-glance/src/test/resources/keystoneAuthResponseVersionedGlanceEndpoint.json
----------------------------------------------------------------------
diff --git 
a/openstack-glance/src/test/resources/keystoneAuthResponseVersionedGlanceEndpoint.json
 
b/openstack-glance/src/test/resources/keystoneAuthResponseVersionedGlanceEndpoint.json
new file mode 100644
index 0000000..77d169a
--- /dev/null
+++ 
b/openstack-glance/src/test/resources/keystoneAuthResponseVersionedGlanceEndpoint.json
@@ -0,0 +1,194 @@
+{
+    "access": {
+        "token": {
+            "expires": "2012-01-18T21:35:59.050Z",
+            "id": "Auth_4f173437e4b013bee56d1007",
+            "tenant": {
+                "id": "40806637803162",
+                "name": "[email protected]"
+            }
+        },
+        "user": {
+            "id": "36980896575174",
+            "name": "[email protected]",
+            "roles": [
+                {
+                    "id": "00000000004022",
+                    "serviceId": "110",
+                    "name": "Admin",
+                    "tenantName": "40806637803162"
+                },
+                {
+                    "id": "00000000004024",
+                    "serviceId": "140",
+                    "name": "user",
+                    "tenantName": "40806637803162"
+                },
+                {
+                    "id": "00000000004004",
+                    "serviceId": "100",
+                    "name": "domainuser"
+                },
+                {
+                    "id": "00000000004016",
+                    "serviceId": "120",
+                    "name": "netadmin",
+                    "tenantName": "40806637803162"
+                }
+            ]
+        },
+        "serviceCatalog": [
+            {
+                "name": "Object Storage",
+                "type": "object-store",
+                "endpoints": [
+                    {
+                        "tenantName": "40806637803162",
+                        "adminURL": "https://objects.jclouds.org/v1.0/";,
+                        "publicURL": 
"https://objects.jclouds.org/v1.0/40806637803162";,
+                        "region": "region-a.geo-1",
+                        "id": "1.0"
+                    }
+                ]
+            },
+            {
+                "name": "Identity",
+                "type": "identity",
+                "endpoints": [
+                    {
+                        "adminURL": "https://csnode.jclouds.org:35357/v2.0/";,
+                        "publicURL": "https://csnode.jclouds.org/v2.0/";,
+                        "region": "region-a.geo-1",
+                        "id": "2.0",
+                        "versionId": "2.0",
+                        "list": "https://csnode.jclouds.org/extension";
+                    }
+                ]
+            },
+            {
+                "name": "Image Management",
+                "type": "image",
+                "endpoints": [
+                    {
+                        "tenantName": "40806637803162",
+                        "publicURL": "https://glance.jclouds.org:9292/v1.0/";,
+                        "region": "az-1.region-a.geo-1",
+                        "id": "1.0"
+                    }
+                ]
+            },
+            {
+                "name": "Compute",
+                "type": "compute",
+                "endpoints": [
+                    {
+                        "tenantId": "3456",
+                        "publicURL": 
"https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456";,
+                        "publicURL2": 
"https://az-1.region-a.geo-1.ec2-compute.hpcloudsvc.com/services/Cloud";,
+                        "region": "az-1.region-a.geo-1",
+                        "versionId": "1.1",
+                        "versionInfo": 
"https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/";,
+                        "versionList": 
"https://az-1.region-a.geo-1.compute.hpcloudsvc.com";
+                    },
+                    {
+                        "tenantId": "3456",
+                        "publicURL": 
"https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456";,
+                        "publicURL2": 
"https://az-2.region-a.geo-1.ec2-compute.hpcloudsvc.com/services/Cloud";,
+                        "region": "az-2.region-a.geo-1",
+                        "versionId": "1.1",
+                        "versionInfo": 
"https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v1.1/";,
+                        "versionList": 
"https://az-2.region-a.geo-1.compute.hpcloudsvc.com";
+                    },
+                    {
+                        "tenantId": "3456",
+                        "publicURL": 
"https://az-3.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456";,
+                        "publicURL2": 
"https://az-3.region-a.geo-1.ec2-compute.hpcloudsvc.com/services/Cloud";,
+                        "region": "az-3.region-a.geo-1",
+                        "versionId": "1.1",
+                        "versionInfo": 
"https://az-3.region-a.geo-1.compute.hpcloudsvc.com/v1.1/";,
+                        "versionList": 
"https://az-3.region-a.geo-1.compute.hpcloudsvc.com";
+                    }
+                ]
+            },
+            {
+                "type": "network",
+                "name": "Neutron Service",
+                "endpoints": [
+                    {
+                        "tenantId": "3456",
+                        "adminURL": "https://csnode.jclouds.org:9696/v1.0";,
+                        "region": "region-a.geo-1",
+                        "versionId": "1.0",
+                        "publicURL": 
"https://csnode.jclouds.org:9696/v1.0/tenants/3456";,
+                        "internalURL": 
"https://csnode.jclouds.org:9696/v1.0/tenants/3456";
+                    }
+                ],
+                "endpoints_links": []
+            },
+            {
+                "type": "network",
+                "name": "Quantum Service",
+                "endpoints": [
+                    {
+                        "tenantId": "3456",
+                        "adminURL": "https://csnode.jclouds.org:9696";,
+                        "region": "region-a.geo-1",
+                        "versionId": "2.0",
+                        "publicURL": "https://csnode.jclouds.org:9696";,
+                        "internalURL": "https://csnode.jclouds.org:9696";
+                    }
+                ],
+                "endpoints_links": []
+            },
+            {
+                "type": "volume",
+                "name": "cinder",
+                "endpoints": [
+                    {
+                        "adminURL": 
"http://10.0.2.15:8776/v1/50cdb4c60374463198695d9f798fa34d";,
+                        "region": "RegionOne",
+                        "internalURL": 
"http://10.0.2.15:8776/v1/50cdb4c60374463198695d9f798fa34d";,
+                        "id": "08330c2dcbfc4c6c8dc7a0949fbf5da7",
+                        "publicURL": 
"http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d";
+                    }
+                ],
+                "endpoints_links": []
+            },
+            {
+                "type": "databases",
+                "name": "reddwarf",
+                "endpoints": [
+                  {
+                    "publicURL": "http://172.16.0.1:8776/v1/3456";,
+                    "tenantId": "123123",
+                    "region": "RegionOne"
+                  }
+                ]
+            },
+            {
+                "type": "queuing",
+                "name": "marconi",
+                "endpoints": [
+                    {
+                        "adminURL": "http://10.0.2.15:8888";,
+                        "region": "RegionOne",
+                        "internalURL": "http://10.0.2.15:8888";,
+                        "id": "3456789",
+                        "publicURL": "http://172.16.0.1:8888";
+                    }
+                ],
+                "endpoints_links": []
+            },
+            {
+                "type": "dns",
+                "name": "dns",
+                "endpoints": [
+                    {
+                        "publicURL": "http://172.16.0.1:8776/v1/3456";,
+                        "tenantId": "3456"
+                    }
+                ]
+            }
+        ]
+    }
+}

Reply via email to