default region endpoint for rackspace legacy apis

This commit is contained in:
Adrian Cole 2012-08-29 23:47:05 -07:00
parent 60f9516dbd
commit c0e8470952
11 changed files with 317 additions and 29 deletions

View File

@ -18,7 +18,7 @@
*/
package org.jclouds.cloudfiles.config;
import static org.jclouds.util.Suppliers2.getLastValueInMap;
import static org.jclouds.util.Suppliers2.valueForKey;
import java.net.URI;
@ -29,12 +29,12 @@ import org.jclouds.cloudfiles.CloudFilesAsyncClient;
import org.jclouds.cloudfiles.CloudFilesClient;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.openstack.keystone.v1_1.config.AuthenticationServiceModule;
import org.jclouds.openstack.keystone.v1_1.suppliers.V1DefaultRegionIdSupplier;
import org.jclouds.openstack.swift.CommonSwiftAsyncClient;
import org.jclouds.openstack.swift.CommonSwiftClient;
import org.jclouds.openstack.swift.Storage;
import org.jclouds.openstack.swift.config.SwiftRestClientModule;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.annotations.ApiVersion;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
@ -62,15 +62,19 @@ public class CloudFilesRestClientModule extends SwiftRestClientModule<CloudFiles
@Provides
@Singleton
@CDNManagement
protected Supplier<URI> provideCDNUrl(RegionIdToURISupplier.Factory factory, @ApiVersion String apiVersion) {
return getLastValueInMap(factory.createForApiTypeAndVersion("cloudFilesCDN", apiVersion));
protected Supplier<URI> provideCDNUrl(RegionIdToURISupplier.Factory factory,
V1DefaultRegionIdSupplier.Factory defaultRegion) {
return valueForKey(factory.createForApiTypeAndVersion("cloudFilesCDN", null),
defaultRegion.createForApiType("cloudFilesCDN"));
}
@Provides
@Singleton
@Storage
protected Supplier<URI> provideStorageUrl(RegionIdToURISupplier.Factory factory, @ApiVersion String apiVersion) {
return getLastValueInMap(factory.createForApiTypeAndVersion("cloudFiles", apiVersion));
protected Supplier<URI> provideStorageUrl(RegionIdToURISupplier.Factory factory,
V1DefaultRegionIdSupplier.Factory defaultRegion) {
return valueForKey(factory.createForApiTypeAndVersion("cloudFiles", null),
defaultRegion.createForApiType("cloudFiles"));
}
}

View File

@ -0,0 +1,56 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.cloudfiles;
import org.jclouds.cloudfiles.internal.BaseCloudFilesRestClientExpectTest;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.testng.annotations.Test;
/**
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "CloudFilesClientExpectTest")
public class CloudFilesClientExpectTest extends BaseCloudFilesRestClientExpectTest {
public void deleteContainerReturnsTrueOn200And404() {
HttpRequest deleteContainer = HttpRequest
.builder()
.method("DELETE")
.endpoint(
"https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953/container")
.addHeader("X-Auth-Token", authToken).build();
HttpResponse containerDeleted = HttpResponse.builder().statusCode(204).message("HTTP/1.1 204 No Content").build();
CloudFilesClient clientWhenContainerExists = requestsSendResponses(initialAuth, responseWithAuth, deleteContainer,
containerDeleted);
assert clientWhenContainerExists.deleteContainerIfEmpty("container");
HttpResponse containerNotFound = HttpResponse.builder().statusCode(404).message("HTTP/1.1 404 Not Found").build();
CloudFilesClient clientWhenContainerDoesntExist = requestsSendResponses(initialAuth, responseWithAuth, deleteContainer,
containerNotFound);
assert clientWhenContainerDoesntExist.deleteContainerIfEmpty("container");
}
}

View File

@ -0,0 +1,51 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.cloudfiles.internal;
import java.util.Properties;
import org.jclouds.apis.ApiMetadata;
import org.jclouds.cloudfiles.CloudFilesApiMetadata;
import org.jclouds.cloudfiles.CloudFilesClient;
import org.jclouds.openstack.keystone.v1_1.internal.BaseKeystoneRestClientExpectTest;
/**
* Base class for writing CloudFiles Rest Client Expect tests
*
* @author Adrian Cole
*/
public class BaseCloudFilesRestClientExpectTest extends BaseKeystoneRestClientExpectTest<CloudFilesClient> {
public BaseCloudFilesRestClientExpectTest() {
provider = "cloudfiles";
}
@Override
protected Properties setupProperties() {
Properties overrides = new Properties();
overrides.setProperty(provider + ".endpoint", endpoint);
return overrides;
}
@Override
protected ApiMetadata createApiMetadata() {
return new CloudFilesApiMetadata();
}
}

View File

@ -29,7 +29,6 @@ import org.jclouds.cloudservers.CloudServersClient;
import org.jclouds.cloudservers.config.CloudServersRestClientModule;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.openstack.filters.AddTimestampQuery;
import org.jclouds.openstack.keystone.v1_1.config.AuthenticationServiceModule;
import org.jclouds.openstack.keystone.v1_1.internal.BaseKeystoneRestClientExpectTest;
import org.jclouds.rest.ConfiguresRestClient;
@ -67,13 +66,6 @@ public class BaseCloudServersRestClientExpectTest extends BaseKeystoneRestClient
* override so that we can control the timestamp used in
* {@link AddTimestampQuery}
*/
public static class TestAuthenticationServiceModule extends AuthenticationServiceModule {
@Override
protected void configure() {
super.configure();
}
}
@Override
protected Module createModule() {
return new TestCloudServersRestClientModule();

View File

@ -33,6 +33,7 @@ import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.location.Provider;
import org.jclouds.location.suppliers.ImplicitRegionIdSupplier;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.openstack.internal.Authentication;
import org.jclouds.openstack.keystone.v1_1.AuthenticationAsyncClient;
@ -40,6 +41,7 @@ import org.jclouds.openstack.keystone.v1_1.AuthenticationClient;
import org.jclouds.openstack.keystone.v1_1.domain.Auth;
import org.jclouds.openstack.keystone.v1_1.handlers.RetryOnRenew;
import org.jclouds.openstack.keystone.v1_1.suppliers.RegionIdToURIFromAuthForServiceSupplier;
import org.jclouds.openstack.keystone.v1_1.suppliers.V1DefaultRegionIdSupplier;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
@ -66,6 +68,8 @@ public class AuthenticationServiceModule extends AbstractModule {
bindClientAndAsyncClient(binder(), AuthenticationClient.class, AuthenticationAsyncClient.class);
install(new FactoryModuleBuilder().implement(RegionIdToURISupplier.class,
RegionIdToURIFromAuthForServiceSupplier.class).build(RegionIdToURISupplier.Factory.class));
install(new FactoryModuleBuilder().implement(ImplicitRegionIdSupplier.class, V1DefaultRegionIdSupplier.class)
.build(V1DefaultRegionIdSupplier.Factory.class));
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(RetryOnRenew.class);
}

View File

@ -22,12 +22,11 @@ import java.net.URI;
import java.util.Collection;
import java.util.Map;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.logging.Logger;
import org.jclouds.openstack.keystone.v1_1.domain.Auth;
import org.jclouds.openstack.keystone.v1_1.domain.Endpoint;
import org.jclouds.openstack.keystone.v1_1.functions.EndpointToRegion;
@ -39,29 +38,24 @@ import com.google.inject.assistedinject.Assisted;
@Singleton
public class RegionIdToURIFromAuthForServiceSupplier implements RegionIdToURISupplier {
@Resource
protected Logger logger = Logger.NULL;
private final Supplier<Auth> auth;
private final EndpointToSupplierURI endpointToSupplierURI;
private final EndpointToRegion endpointToRegion;
private final String apiType;
private final String apiVersion;
@Inject
public RegionIdToURIFromAuthForServiceSupplier(Supplier<Auth> auth, EndpointToSupplierURI endpointToSupplierURI,
EndpointToRegion endpointToRegion, @Assisted("apiType") String apiType,
@Assisted("apiVersion") String apiVersion) {
@Nullable @Assisted("apiVersion") String apiVersion) {
this.auth = auth;
this.endpointToSupplierURI = endpointToSupplierURI;
this.endpointToRegion = endpointToRegion;
this.apiType = apiType;
this.apiVersion = apiVersion;
}
@Override
public Map<String, Supplier<URI>> get() {
logger.trace("current version of keystone doesn't allow us to validate the apiVersion %s", apiVersion);
Auth authResponse = auth.get();
Collection<Endpoint> endpointsForService = authResponse.getServiceCatalog().get(apiType);
Map<String, Endpoint> regionIdToEndpoint = Maps.uniqueIndex(endpointsForService, endpointToRegion);

View File

@ -0,0 +1,87 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.keystone.v1_1.suppliers;
import static com.google.common.collect.Iterables.tryFind;
import java.util.NoSuchElementException;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.location.suppliers.ImplicitRegionIdSupplier;
import org.jclouds.openstack.keystone.v1_1.domain.Auth;
import org.jclouds.openstack.keystone.v1_1.domain.Endpoint;
import org.jclouds.openstack.keystone.v1_1.functions.EndpointToRegion;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;
import com.google.inject.assistedinject.Assisted;
@Singleton
public class V1DefaultRegionIdSupplier implements ImplicitRegionIdSupplier {
public static interface Factory {
/**
*
* @param apiType
* type of the api, according to the provider. ex. {@code compute}
* {@code object-store}
* @return region id
* @throws NoSuchElementException
* if the {@code apiType} is not present in the catalog
*/
ImplicitRegionIdSupplier createForApiType(@Assisted("apiType") String apiType) throws NoSuchElementException;
}
private final Supplier<Auth> auth;
private final EndpointToRegion endpointToRegion;
private final String apiType;
@Inject
public V1DefaultRegionIdSupplier(Supplier<Auth> auth, EndpointToRegion endpointToRegion,
@Assisted("apiType") String apiType) {
this.auth = auth;
this.endpointToRegion = endpointToRegion;
this.apiType = apiType;
}
/**
* returns {@link Endpoint#isV1Default()} or first endpoint for service
*/
@Override
public String get() {
Auth authResponse = auth.get();
Iterable<Endpoint> endpointsForService = authResponse.getServiceCatalog().get(apiType);
Optional<Endpoint> defaultEndpoint = tryFind(endpointsForService, new Predicate<Endpoint>() {
@Override
public boolean apply(Endpoint in) {
return in.isV1Default();
}
});
return endpointToRegion.apply(defaultEndpoint.or(Iterables.get(endpointsForService, 0)));
}
@Override
public String toString() {
return "defaultRegionIdFor(" + apiType + ")";
}
}

View File

@ -53,7 +53,6 @@ public class RegionIdToURIFromAuthForServiceSupplierTest {
RegionIdToURIFromAuthForServiceSupplier.class).build(RegionIdToURISupplier.Factory.class));
}
@SuppressWarnings("unused")
@Provides
@Singleton
public Supplier<Auth> provide() {

View File

@ -0,0 +1,66 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.keystone.v1_1.suppliers;
import static org.testng.Assert.assertEquals;
import javax.inject.Singleton;
import org.jclouds.location.Provider;
import org.jclouds.location.suppliers.ImplicitRegionIdSupplier;
import org.jclouds.openstack.keystone.v1_1.domain.Auth;
import org.jclouds.openstack.keystone.v1_1.parse.ParseAuthTest;
import org.testng.annotations.Test;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Provides;
import com.google.inject.assistedinject.FactoryModuleBuilder;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "V1DefaultRegionIdSupplierTest")
public class V1DefaultRegionIdSupplierTest {
private final V1DefaultRegionIdSupplier.Factory factory = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bindConstant().annotatedWith(Provider.class).to("keystone");
install(new FactoryModuleBuilder().implement(ImplicitRegionIdSupplier.class, V1DefaultRegionIdSupplier.class)
.build(V1DefaultRegionIdSupplier.Factory.class));
}
@Provides
@Singleton
public Supplier<Auth> provide() {
return Suppliers.ofInstance(new ParseAuthTest().expected());
}
}).getInstance(V1DefaultRegionIdSupplier.Factory.class);
public void testRegionMatches() {
assertEquals(factory.createForApiType("cloudFilesCDN").get(), "LON");
}
public void testTakesFirstPartOfDNSWhenNoRegion() {
assertEquals(factory.createForApiType("cloudServers").get(), "lon");
}
}

View File

@ -41,20 +41,39 @@ import com.google.common.io.OutputSupplier;
*/
public class Suppliers2 {
public static <K, V> Supplier<V> getLastValueInMap(Supplier<Map<K, Supplier<V>>> input) {
return Suppliers2.compose(new Function<Map<K, Supplier<V>>, V>() {
/**
* Supplies a value that corresponds to a particular key in a map, or null, if not found
*/
public static <K, V> Supplier<V> valueForKey(final Supplier<Map<K, Supplier<V>>> input, final Supplier<K> key) {
return new Supplier<V>() {
@Override
public V apply(Map<K, Supplier<V>> input) {
Supplier<V> last = Iterables.getLast(input.values());
return last.get();
public V get() {
K keyToFind = key.get();
Supplier<V> value = input.get().get(keyToFind);
return value != null ? value.get() : null;
}
@Override
public String toString() {
return "withKey()";
}
};
}
public static <K, V> Supplier<V> getLastValueInMap(final Supplier<Map<K, Supplier<V>>> input) {
return new Supplier<V>() {
@Override
public V get() {
Supplier<V> last = Iterables.getLast(input.get().values());
return last != null ? last.get() : null;
}
@Override
public String toString() {
return "getLastValueInMap()";
}
}, input);
};
}
public static <X> Function<X, Supplier<X>> ofInstanceFunction() {

View File

@ -31,6 +31,22 @@ import com.google.common.collect.ImmutableMap;
public class Suppliers2Test {
@Test
public void testWithKey() {
assertEquals(
Suppliers2.<String, String> valueForKey(
Suppliers.<Map<String, Supplier<String>>> ofInstance(ImmutableMap.of("foo",
Suppliers.ofInstance("bar"))), Suppliers.ofInstance("foo")).get(), "bar");
}
@Test
public void testWithKeyUnmatchedIsNull() {
assertEquals(
Suppliers2.<String, String> valueForKey(
Suppliers.<Map<String, Supplier<String>>> ofInstance(ImmutableMap.of("boo",
Suppliers.ofInstance("bar"))), Suppliers.ofInstance("foo")).get(), null);
}
@Test
public void testGetLastValueInMap() {
assertEquals(