made openstack multi-region, and now select correct endpoint via apiversion property

This commit is contained in:
Adrian Cole 2012-02-04 00:50:17 -08:00
parent 61314015dc
commit ae1effd748
58 changed files with 1354 additions and 511 deletions

View File

@ -18,6 +18,7 @@
*/
package org.jclouds.cloudfiles.config;
import static org.jclouds.util.Suppliers2.getLastValueInMap;
import java.net.URI;
@ -27,22 +28,21 @@ import org.jclouds.cloudfiles.CDNManagement;
import org.jclouds.cloudfiles.CloudFilesAsyncClient;
import org.jclouds.cloudfiles.CloudFilesClient;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError;
import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.openstack.keystone.v1_1.config.AuthenticationServiceModule;
import org.jclouds.openstack.keystone.v1_1.functions.PublicURLFromAuthResponseForService;
import org.jclouds.openstack.keystone.v1_1.handlers.RetryOnRenew;
import org.jclouds.openstack.swift.CommonSwiftAsyncClient;
import org.jclouds.openstack.swift.CommonSwiftClient;
import org.jclouds.openstack.swift.Storage;
import org.jclouds.openstack.swift.config.SwiftObjectModule;
import org.jclouds.openstack.swift.handlers.ParseSwiftErrorFromHttpResponse;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.annotations.ApiVersion;
import org.jclouds.rest.config.RestClientModule;
import com.google.common.base.Supplier;
@ -55,15 +55,9 @@ import com.google.inject.Provides;
@ConfiguresRestClient
@RequiresHttp
public class CloudFilesRestClientModule extends RestClientModule<CloudFilesClient, CloudFilesAsyncClient> {
private final AuthenticationServiceModule module;
public CloudFilesRestClientModule(AuthenticationServiceModule module) {
super(CloudFilesClient.class, CloudFilesAsyncClient.class);
this.module = module;
}
public CloudFilesRestClientModule() {
this(new AuthenticationServiceModule());
super(CloudFilesClient.class, CloudFilesAsyncClient.class);
}
@Provides
@ -78,23 +72,8 @@ public class CloudFilesRestClientModule extends RestClientModule<CloudFilesClien
return in;
}
@Provides
@Singleton
@CDNManagement
protected Supplier<URI> provideCDNUrl(PublicURLFromAuthResponseForService.Factory factory) {
return factory.create("cloudFilesCDN");
}
@Provides
@Singleton
@Storage
protected Supplier<URI> provideStorageUrl(PublicURLFromAuthResponseForService.Factory factory) {
return factory.create("cloudFiles");
}
@Override
protected void configure() {
install(module);
install(new SwiftObjectModule());
bind(DateAdapter.class).to(Iso8601DateAdapter.class);
super.configure();
@ -108,9 +87,23 @@ public class CloudFilesRestClientModule extends RestClientModule<CloudFilesClien
}
@Override
protected void bindRetryHandlers() {
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(RetryOnRenew.class);
protected void installLocations() {
super.installLocations();
install(new AuthenticationServiceModule());
}
@Provides
@Singleton
@CDNManagement
protected Supplier<URI> provideCDNUrl(RegionIdToURISupplier.Factory factory, @ApiVersion String apiVersion) {
return getLastValueInMap(factory.createForApiTypeAndVersion("cloudFilesCDN", apiVersion));
}
@Provides
@Singleton
@Storage
protected Supplier<URI> provideStorageUrl(RegionIdToURISupplier.Factory factory, @ApiVersion String apiVersion) {
return getLastValueInMap(factory.createForApiTypeAndVersion("cloudFiles", apiVersion));
}
}

View File

@ -18,6 +18,8 @@
*/
package org.jclouds.cloudloadbalancers.config;
import static org.jclouds.util.Suppliers2.getLastValueInMap;
import java.net.URI;
import java.util.Map;
@ -35,28 +37,26 @@ import org.jclouds.cloudloadbalancers.handlers.ParseCloudLoadBalancersErrorFromH
import org.jclouds.cloudloadbalancers.location.RegionUrisFromPropertiesAndAccountIDPathSuffix;
import org.jclouds.cloudloadbalancers.reference.RackspaceConstants;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError;
import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
import org.jclouds.location.Region;
import org.jclouds.location.config.LocationModule;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.openstack.keystone.v1_1.config.AuthenticationServiceModule;
import org.jclouds.openstack.keystone.v1_1.functions.PublicURLFromAuthResponseForService;
import org.jclouds.openstack.keystone.v1_1.handlers.RetryOnRenew;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.annotations.ApiVersion;
import org.jclouds.rest.config.RestClientModule;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder;
/**
@ -67,75 +67,65 @@ import com.google.inject.assistedinject.FactoryModuleBuilder;
@RequiresHttp
@ConfiguresRestClient
public class CloudLoadBalancersRestClientModule extends
RestClientModule<CloudLoadBalancersClient, CloudLoadBalancersAsyncClient> {
RestClientModule<CloudLoadBalancersClient, CloudLoadBalancersAsyncClient> {
public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()//
.put(LoadBalancerClient.class, LoadBalancerAsyncClient.class)//
.put(NodeClient.class, NodeAsyncClient.class)//
.build();
private final AuthenticationServiceModule module;
public CloudLoadBalancersRestClientModule(AuthenticationServiceModule module) {
super(CloudLoadBalancersClient.class, CloudLoadBalancersAsyncClient.class, DELEGATE_MAP);
this.module = module;
}
.put(LoadBalancerClient.class, LoadBalancerAsyncClient.class)//
.put(NodeClient.class, NodeAsyncClient.class)//
.build();
public CloudLoadBalancersRestClientModule() {
this(new AuthenticationServiceModule());
super(CloudLoadBalancersClient.class, CloudLoadBalancersAsyncClient.class, DELEGATE_MAP);
}
@Override
protected void installLocations() {
super.installLocations();
bind(RegionIdToURISupplier.class).to(RegionUrisFromPropertiesAndAccountIDPathSuffix.class).in(Scopes.SINGLETON);
install(new LocationModule());
install(new URIWithAccountIDPathSuffixAuthenticationServiceModule());
}
protected void bindRegionsToProvider(Class<? extends javax.inject.Provider<Map<String, URI>>> providerClass) {
bind(new TypeLiteral<Map<String, URI>>() {
}).annotatedWith(Region.class).toProvider(providerClass).in(Scopes.SINGLETON);
public static class URIWithAccountIDPathSuffixAuthenticationServiceModule extends AbstractModule {
@Override
protected void configure() {
install(new AuthenticationServiceModule());
bind(RegionIdToURISupplier.class).to(RegionUrisFromPropertiesAndAccountIDPathSuffix.class)
.in(Scopes.SINGLETON);
}
@Provides
@Singleton
@Named(RackspaceConstants.PROPERTY_ACCOUNT_ID)
protected Supplier<String> accountID(RegionIdToURISupplier.Factory factory, @ApiVersion String apiVersion) {
return Suppliers.compose(new Function<URI, String>() {
@Override
public String apply(URI arg0) {
return arg0.getPath().substring(arg0.getPath().lastIndexOf('/') + 1);
}
@Override
public String toString() {
return "getAccountIdFromCloudServers()";
}
}, getLastValueInMap(factory.createForApiTypeAndVersion("cloudServers", apiVersion)));
}
}
@Override
protected void configure() {
install(module);
bind(DateAdapter.class).to(Iso8601DateAdapter.class);
install(new FactoryModuleBuilder().build(ConvertLB.Factory.class));
super.configure();
}
@Provides
@Singleton
@Named(RackspaceConstants.PROPERTY_ACCOUNT_ID)
protected Supplier<String> accountID(PublicURLFromAuthResponseForService.Factory factory) {
return Suppliers.compose(new Function<URI, String>() {
@Override
public String apply(URI arg0) {
return arg0.getPath().substring(arg0.getPath().lastIndexOf('/') + 1);
}
@Override
public String toString() {
return "getAccountIdFromCloudServers()";
}
}, factory.create("cloudServers"));
}
@Override
protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(
ParseCloudLoadBalancersErrorFromHttpResponse.class);
ParseCloudLoadBalancersErrorFromHttpResponse.class);
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(
ParseCloudLoadBalancersErrorFromHttpResponse.class);
ParseCloudLoadBalancersErrorFromHttpResponse.class);
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(
ParseCloudLoadBalancersErrorFromHttpResponse.class);
ParseCloudLoadBalancersErrorFromHttpResponse.class);
}
@Override
protected void bindRetryHandlers() {
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(RetryOnRenew.class);
}
}

View File

@ -42,8 +42,8 @@ import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.RequiresHttp;
import org.jclouds.internal.ClassMethodArgs;
import org.jclouds.location.config.LocationModule;
import org.jclouds.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v1_1.config.AuthenticationServiceModule;
import org.jclouds.openstack.keystone.v1_1.config.AuthenticationServiceModule.GetAuth;
import org.jclouds.openstack.keystone.v1_1.domain.Auth;
import org.jclouds.openstack.keystone.v1_1.parse.ParseAuthTest;
@ -55,6 +55,7 @@ import org.testng.annotations.BeforeClass;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableSet;
import com.google.inject.AbstractModule;
import com.google.inject.Module;
import com.google.inject.Provides;
@ -77,21 +78,27 @@ public abstract class BaseCloudLoadBalancersAsyncClientTest<T> extends RestClien
@ConfiguresRestClient
@RequiresHttp
protected static class TestCloudLoadBalancersRestClientModule extends CloudLoadBalancersRestClientModule {
private TestCloudLoadBalancersRestClientModule() {
super(new AuthenticationServiceModule());
}
@Provides
@Singleton
GetAuth provideGetAuth() {
return new GetAuth(null) {
@Override
public Auth apply(Credentials in) {
return new ParseAuthTest().expected();
@Override
protected void installLocations() {
install(new AbstractModule() {
protected void configure() {
}
};
}
@Provides
@Singleton
GetAuth provideGetAuth() {
return new GetAuth(null) {
@Override
public Auth apply(Credentials in) {
return new ParseAuthTest().expected();
}
};
}
});
install(new LocationModule());
install(new URIWithAccountIDPathSuffixAuthenticationServiceModule());
}
}
@Override
@ -106,8 +113,8 @@ public abstract class BaseCloudLoadBalancersAsyncClientTest<T> extends RestClien
super.setupFactory();
try {
processor.setCaller(new ClassMethodArgs(CloudLoadBalancersAsyncClient.class,
CloudLoadBalancersAsyncClient.class.getMethod("getLoadBalancerClient", String.class),
new Object[] { Region.LON }));
CloudLoadBalancersAsyncClient.class.getMethod("getLoadBalancerClient", String.class),
new Object[] { Region.LON }));
} catch (Exception e) {
Throwables.propagate(e);
}
@ -119,20 +126,20 @@ public abstract class BaseCloudLoadBalancersAsyncClientTest<T> extends RestClien
overrides.setProperty(provider + ".endpoint", "https://auth");
overrides.setProperty(PROPERTY_REGIONS, LON);
overrides.setProperty(PROPERTY_REGION + "." + LON + "." + ISO3166_CODES, "GB-SLG");
overrides.setProperty(PROPERTY_REGION + "." + LON + "." + ENDPOINT,
String.format("https://lon.loadbalancers.api.rackspacecloud.com/v${%s}", PROPERTY_API_VERSION));
overrides.setProperty(PROPERTY_REGION + "." + LON + "." + ENDPOINT, String.format(
"https://lon.loadbalancers.api.rackspacecloud.com/v${%s}", PROPERTY_API_VERSION));
return overrides;
}
/**
* this is only here as "cloudloadbalancers" is not in rest.properties
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings( { "unchecked", "rawtypes" })
@Override
public RestContextSpec<?, ?> createContextSpec() {
return RestContextFactory.<LoadBalancerClient, LoadBalancerAsyncClient> contextSpec(provider, "https://auth",
"1.0", "", "", "identity", "credential", LoadBalancerClient.class, LoadBalancerAsyncClient.class,
(Class)CloudLoadBalancersPropertiesBuilder.class, (Class)CloudLoadBalancersContextBuilder.class,
ImmutableSet.<Module> of());
"1.0", "", "", "identity", "credential", LoadBalancerClient.class, LoadBalancerAsyncClient.class,
(Class) CloudLoadBalancersPropertiesBuilder.class, (Class) CloudLoadBalancersContextBuilder.class,
ImmutableSet.<Module> of());
}
}

View File

@ -19,6 +19,7 @@
package org.jclouds.cloudservers.config;
import static com.google.common.base.Suppliers.memoizeWithExpiration;
import static org.jclouds.util.Suppliers2.getLastValueInMap;
import java.net.URI;
import java.util.Date;
@ -31,18 +32,17 @@ import org.jclouds.cloudservers.CloudServersClient;
import org.jclouds.cloudservers.handlers.ParseCloudServersErrorFromHttpResponse;
import org.jclouds.date.TimeStamp;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError;
import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.openstack.keystone.v1_1.config.AuthenticationServiceModule;
import org.jclouds.openstack.keystone.v1_1.functions.PublicURLFromAuthResponseForService;
import org.jclouds.openstack.keystone.v1_1.handlers.RetryOnRenew;
import org.jclouds.openstack.services.Compute;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.annotations.ApiVersion;
import org.jclouds.rest.config.RestClientModule;
import com.google.common.base.Supplier;
@ -56,20 +56,12 @@ import com.google.inject.Provides;
@RequiresHttp
public class CloudServersRestClientModule extends RestClientModule<CloudServersClient, CloudServersAsyncClient> {
private final AuthenticationServiceModule module;
public CloudServersRestClientModule(AuthenticationServiceModule module) {
super(CloudServersClient.class, CloudServersAsyncClient.class);
this.module = module;
}
public CloudServersRestClientModule() {
this(new AuthenticationServiceModule());
super(CloudServersClient.class, CloudServersAsyncClient.class);
}
@Override
protected void configure() {
install(module);
bind(DateAdapter.class).to(Iso8601DateAdapter.class);
super.configure();
}
@ -82,18 +74,19 @@ public class CloudServersRestClientModule extends RestClientModule<CloudServersC
}
@Override
protected void bindRetryHandlers() {
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(RetryOnRenew.class);
protected void installLocations() {
super.installLocations();
install(new AuthenticationServiceModule());
}
@Provides
@Singleton
@Compute
protected Supplier<URI> provideServerUrl(PublicURLFromAuthResponseForService.Factory factory) {
return factory.create("cloudServers");
protected Supplier<URI> provideCloudServers(RegionIdToURISupplier.Factory factory, @ApiVersion String apiVersion) {
return getLastValueInMap(factory.createForApiTypeAndVersion("cloudServers", apiVersion));
}
//TODO: see if we still need this.
// TODO: see if we still need this.
@Provides
@Singleton
@TimeStamp

View File

@ -43,7 +43,6 @@ import org.jclouds.cloudservers.domain.BackupSchedule;
import org.jclouds.cloudservers.domain.DailyBackup;
import org.jclouds.cloudservers.domain.RebootType;
import org.jclouds.cloudservers.domain.WeeklyBackup;
import org.jclouds.cloudservers.internal.BaseCloudServersRestClientExpectTest.TestAuthenticationServiceModule;
import org.jclouds.cloudservers.options.CreateServerOptions;
import org.jclouds.cloudservers.options.CreateSharedIpGroupOptions;
import org.jclouds.cloudservers.options.ListOptions;
@ -894,9 +893,6 @@ public class CloudServersAsyncClientTest extends RestClientTest<CloudServersAsyn
@ConfiguresRestClient
@RequiresHttp
protected static class TestCloudServersRestClientModule extends CloudServersRestClientModule {
private TestCloudServersRestClientModule() {
super(new TestAuthenticationServiceModule());
}
@Provides
@Singleton

View File

@ -79,9 +79,6 @@ public class BaseCloudServersRestClientExpectTest extends BaseKeystoneRestClient
@ConfiguresRestClient
@RequiresHttp
protected static class TestCloudServersRestClientModule extends CloudServersRestClientModule {
private TestCloudServersRestClientModule() {
super(new TestAuthenticationServiceModule());
}
@Override
public Supplier<Date> provideCacheBusterDate() {

View File

@ -18,12 +18,8 @@
*/
package org.jclouds.ec2.config;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.aws.config.WithZonesFormSigningRestClientModule;
import org.jclouds.ec2.EC2AsyncClient;
@ -47,18 +43,14 @@ import org.jclouds.ec2.services.WindowsClient;
import org.jclouds.ec2.suppliers.DescribeAvailabilityZonesInRegion;
import org.jclouds.ec2.suppliers.DescribeRegionsForConfiguredRegions;
import org.jclouds.http.RequiresHttp;
import org.jclouds.location.Zone;
import org.jclouds.location.config.LocationModule;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.location.suppliers.RegionIdToZoneIdsSupplier;
import org.jclouds.location.suppliers.ZoneIdsSupplier;
import org.jclouds.location.suppliers.derived.ZoneIdsFromRegionIdToZoneIdsValues;
import org.jclouds.rest.ConfiguresRestClient;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.inject.Scopes;
/**
@ -97,27 +89,4 @@ public class EC2RestClientModule<S extends EC2Client, A extends EC2AsyncClient>
bind(RegionIdToURISupplier.class).to(DescribeRegionsForConfiguredRegions.class).in(Scopes.SINGLETON);
bind(ZoneIdsSupplier.class).to(ZoneIdsFromRegionIdToZoneIdsValues.class).in(Scopes.SINGLETON);
}
/**
* as opposed to via properties, lets look up zones via api, as they are more likely to change
*/
@Singleton
public static class ZoneIdsFromRegionIdToZoneIdsValues implements ZoneIdsSupplier {
private final Supplier<Map<String, Supplier<Set<String>>>> regionIdToZoneIdsSupplier;
@Inject
protected ZoneIdsFromRegionIdToZoneIdsValues(
@Zone Supplier<Map<String, Supplier<Set<String>>>> regionIdToZoneIdsSupplier) {
this.regionIdToZoneIdsSupplier = regionIdToZoneIdsSupplier;
}
@Override
public Set<String> get() {
Collection<Supplier<Set<String>>> zones = regionIdToZoneIdsSupplier.get().values();
return ImmutableSet.copyOf(Iterables.concat(Iterables.transform(zones, Suppliers
.<Set<String>> supplierFunction())));
}
}
}

View File

@ -77,11 +77,6 @@ public class NovaRestClientModule extends RestClientModule<NovaClient, NovaAsync
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ParseNovaErrorFromHttpResponse.class);
}
@Override
protected void bindRetryHandlers() {
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(RetryOnRenew.class);
}
@Provides
@Singleton
@ServerManagement

View File

@ -23,7 +23,6 @@ import java.net.URI;
import javax.inject.Singleton;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
@ -32,7 +31,6 @@ import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
import org.jclouds.openstack.config.OpenStackAuthenticationModule;
import org.jclouds.openstack.functions.URIFromAuthenticationResponseForService;
import org.jclouds.openstack.handlers.RetryOnRenew;
import org.jclouds.openstack.reference.AuthHeaders;
import org.jclouds.openstack.swift.CommonSwiftAsyncClient;
import org.jclouds.openstack.swift.CommonSwiftClient;
@ -79,11 +77,6 @@ public class BaseSwiftRestClientModule<S extends CommonSwiftClient, A extends Co
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ParseSwiftErrorFromHttpResponse.class);
}
@Override
protected void bindRetryHandlers() {
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(RetryOnRenew.class);
}
@Provides
@Singleton
@Storage

View File

@ -32,13 +32,16 @@ import javax.inject.Singleton;
import org.jclouds.concurrent.RetryOnTimeOutExceptionFunction;
import org.jclouds.date.TimeStamp;
import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.location.Provider;
import org.jclouds.openstack.Authentication;
import org.jclouds.openstack.OpenStackAuthAsyncClient;
import org.jclouds.openstack.OpenStackAuthClient;
import org.jclouds.openstack.domain.AuthenticationResponse;
import org.jclouds.openstack.functions.URIFromAuthenticationResponseForService;
import org.jclouds.openstack.handlers.RetryOnRenew;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
@ -66,6 +69,7 @@ public class OpenStackAuthenticationModule extends AbstractModule {
// explicitly
bindClientAndAsyncClient(binder(), OpenStackAuthClient.class, OpenStackAuthAsyncClient.class);
install(new FactoryModuleBuilder().build(URIFromAuthenticationResponseForService.Factory.class));
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(RetryOnRenew.class);
}
/**

View File

@ -30,13 +30,17 @@ import javax.inject.Singleton;
import org.jclouds.concurrent.RetryOnTimeOutExceptionFunction;
import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.location.Provider;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.openstack.Authentication;
import org.jclouds.openstack.keystone.v1_1.ServiceAsyncClient;
import org.jclouds.openstack.keystone.v1_1.ServiceClient;
import org.jclouds.openstack.keystone.v1_1.domain.Auth;
import org.jclouds.openstack.keystone.v1_1.functions.PublicURLFromAuthResponseForService;
import org.jclouds.openstack.keystone.v1_1.handlers.RetryOnRenew;
import org.jclouds.openstack.keystone.v1_1.suppliers.RegionIdToURIFromAuthForServiceSupplier;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
@ -62,7 +66,9 @@ public class AuthenticationServiceModule extends AbstractModule {
// ServiceClient is used directly for filters and retry handlers, so let's bind it
// explicitly
bindClientAndAsyncClient(binder(), ServiceClient.class, ServiceAsyncClient.class);
install(new FactoryModuleBuilder().build(PublicURLFromAuthResponseForService.Factory.class));
install(new FactoryModuleBuilder().implement(RegionIdToURISupplier.class,
RegionIdToURIFromAuthForServiceSupplier.class).build(RegionIdToURISupplier.Factory.class));
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(RetryOnRenew.class);
}
/**

View File

@ -104,10 +104,10 @@ public class Endpoint implements Comparable<Endpoint> {
protected final URI publicURL;
protected final URI internalURL;
protected Endpoint(boolean v1Default, @Nullable String region, URI publicURL, @Nullable URI internalURL) {
protected Endpoint(boolean v1Default, @Nullable String region, @Nullable URI publicURL, @Nullable URI internalURL) {
this.v1Default = v1Default;
this.region = region;
this.publicURL = checkNotNull(publicURL, "publicURL");
this.publicURL = publicURL;
this.internalURL = internalURL;
}
@ -141,11 +141,12 @@ public class Endpoint implements Comparable<Endpoint> {
}
/**
* A public URL is accessible from anywhere. Access to a public URL usually
* incurs traffic charges.
* A public URL is accessible from anywhere. Access to a public URL usually incurs traffic
* charges.
*
* @return the public endpoint of the service
*/
@Nullable
public URI getPublicURL() {
return publicURL;
}

View File

@ -0,0 +1,29 @@
/**
* 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.functions;
import org.jclouds.openstack.keystone.v1_1.domain.Endpoint;
import com.google.common.base.Function;
import com.google.inject.ImplementedBy;
@ImplementedBy(RegionFirstPartOfDNSNameOrProvider.class)
public interface EndpointToRegion extends Function<Endpoint, String> {
}

View File

@ -18,24 +18,14 @@
*/
package org.jclouds.openstack.keystone.v1_1.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI;
import org.jclouds.openstack.keystone.v1_1.domain.Auth;
import org.jclouds.openstack.keystone.v1_1.domain.Endpoint;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.base.Supplier;
import com.google.inject.ImplementedBy;
public class PublicUrlForService implements Function<Auth, URI> {
private final String serviceId;
public PublicUrlForService(String serviceId) {
this.serviceId = checkNotNull(serviceId, "serviceId");
}
@Override
public URI apply(Auth arg0) {
return Iterables.get(arg0.getServiceCatalog().get(serviceId), 0).getPublicURL();
}
@ImplementedBy(PublicURLOrInternalIfNull.class)
public interface EndpointToSupplierURI extends Function<Endpoint, Supplier<URI>> {
}

View File

@ -0,0 +1,46 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.keystone.v1_1.functions;
import java.net.URI;
import javax.inject.Singleton;
import org.jclouds.openstack.keystone.v1_1.domain.Endpoint;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
@Singleton
public class PublicURLOrInternalIfNull implements EndpointToSupplierURI {
// TODO: check accessibility and prioritize private first
@Override
public Supplier<URI> apply(Endpoint input) {
return Suppliers.ofInstance(input.getPublicURL() != null ? input.getPublicURL() : input.getInternalURL());
}
public String toString() {
return "supplyPublicURL()";
}
}

View File

@ -18,39 +18,32 @@
*/
package org.jclouds.openstack.keystone.v1_1.functions;
import java.net.URI;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.openstack.keystone.v1_1.domain.Auth;
import org.jclouds.location.Provider;
import org.jclouds.openstack.keystone.v1_1.domain.Endpoint;
import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;
import com.google.inject.assistedinject.Assisted;
import com.google.common.net.InternetDomainName;
@Singleton
public class PublicURLFromAuthResponseForService implements Supplier<URI> {
public static interface Factory {
PublicURLFromAuthResponseForService create(String service);
}
private final Supplier<Auth> auth;
private final String service;
public class RegionFirstPartOfDNSNameOrProvider implements EndpointToRegion {
private final String provider;
@Inject
public PublicURLFromAuthResponseForService(Supplier<Auth> auth, @Assisted String service) {
this.auth = auth;
this.service = service;
RegionFirstPartOfDNSNameOrProvider(@Provider String provider) {
this.provider = provider;
}
@Override
public URI get() {
return Iterables.get(auth.get().getServiceCatalog().get(service), 0).getPublicURL();
}
@Override
public String toString() {
return "getPublicURLForService(" + service + ")";
public String apply(Endpoint input) {
if (input.getRegion() != null)
return input.getRegion();
String host = input.getPublicURL().getHost();
if (InternetDomainName.isValid(host)) {
InternetDomainName domain = InternetDomainName.from(host);
return domain.parts().get(0);
}
return provider;
}
}

View File

@ -0,0 +1,75 @@
/**
* 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 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.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;
import org.jclouds.openstack.keystone.v1_1.functions.EndpointToSupplierURI;
import com.google.common.base.Supplier;
import com.google.common.collect.Maps;
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) {
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);
return Maps.transformValues(regionIdToEndpoint, endpointToSupplierURI);
}
@Override
public String toString() {
return "getPublicURLForService(" + apiType + ")";
}
}

View File

@ -53,7 +53,7 @@ public interface ServiceAsyncClient {
@Consumes(MediaType.APPLICATION_JSON)
@Path("/tokens")
@MapBinder(BindAuthToJsonPayload.class)
ListenableFuture<Access> authenticateTenantWithCredentials(@PayloadParam("tenantId") String tenantId,
ListenableFuture<Access> authenticateTenantWithCredentials(@PayloadParam("tenantName") String tenantId,
PasswordCredentials passwordCredentials);
/**
@ -64,6 +64,8 @@ public interface ServiceAsyncClient {
@Consumes(MediaType.APPLICATION_JSON)
@Path("/tokens")
@MapBinder(BindAuthToJsonPayload.class)
ListenableFuture<Access> authenticateTenantWithCredentials(@PayloadParam("tenantId") String tenantId,
// TODO: is tenantName permanent? or should we switch to tenantId at some point. seems most tools
// still use tenantName
ListenableFuture<Access> authenticateTenantWithCredentials(@PayloadParam("tenantName") String tenantId,
ApiAccessKeyCredentials apiAccessKeyCredentials);
}

View File

@ -75,8 +75,10 @@ public class BindAuthToJsonPayload extends BindToJsonPayload implements MapBinde
Builder<String, Object> builder = ImmutableMap.<String, Object> builder();
addCredentialsInArgsOrNull(gRequest, builder);
if (Strings.emptyToNull(postParams.get("tenantId")) != null)
builder.put("tenantId", postParams.get("tenantId"));
// TODO: is tenantName permanent? or should we switch to tenantId at some point. seems most tools
// still use tenantName
if (Strings.emptyToNull(postParams.get("tenantName")) != null)
builder.put("tenantName", postParams.get("tenantName"));
return super.bindToRequest(request, ImmutableMap.of("auth", builder.build()));
}

View File

@ -34,14 +34,18 @@ import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.location.Provider;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.location.suppliers.RegionIdsSupplier;
import org.jclouds.location.suppliers.derived.RegionIdsFromRegionIdToURIKeySet;
import org.jclouds.openstack.Authentication;
import org.jclouds.openstack.keystone.v2_0.ServiceAsyncClient;
import org.jclouds.openstack.keystone.v2_0.ServiceClient;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.functions.AuthenticateApiAccessKeyCredentials;
import org.jclouds.openstack.keystone.v2_0.functions.AuthenticatePasswordCredentials;
import org.jclouds.openstack.keystone.v2_0.functions.PublicURLFromAccessForService;
import org.jclouds.openstack.keystone.v2_0.handlers.RetryOnRenew;
import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToURIFromAccessForTypeAndVersionSupplier;
import org.jclouds.rest.annotations.ApiVersion;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
@ -67,7 +71,19 @@ public class KeystoneAuthenticationModule extends AbstractModule {
// ServiceClient is used directly for filters and retry handlers, so let's bind it
// explicitly
bindClientAndAsyncClient(binder(), ServiceClient.class, ServiceAsyncClient.class);
install(new FactoryModuleBuilder().build(PublicURLFromAccessForService.Factory.class));
install(new FactoryModuleBuilder().implement(RegionIdToURISupplier.class,
RegionIdToURIFromAccessForTypeAndVersionSupplier.class).build(RegionIdToURISupplier.Factory.class));
// dynamically build the region list as opposed to from properties
bind(RegionIdsSupplier.class).to(RegionIdsFromRegionIdToURIKeySet.class);
}
// supply the region to id map from keystone, based on the servicetype and api version in config
@Provides
@Singleton
protected RegionIdToURISupplier provideRegionIdToURISupplierForApiVersion(
@Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion,
RegionIdToURISupplier.Factory factory) {
return factory.createForApiTypeAndVersion(serviceType, apiVersion);
}
/**

View File

@ -18,6 +18,8 @@
*/
package org.jclouds.openstack.keystone.v2_0.config;
import org.jclouds.openstack.services.ServiceType;
/**
* Configuration properties and constants used in Keystone connections.
*
@ -40,4 +42,15 @@ public interface KeystoneProperties {
*/
public static final String CREDENTIAL_TYPE = "jclouds.keystone.credential-type";
/**
* version of the keystone service
*/
public static final String VERSION = "jclouds.keystone.version";
/**
* type of the keystone service. ex. {@code compute}
*
* @see ServiceType
*/
public static final String SERVICE_TYPE = "jclouds.keystone.service-type";
}

View File

@ -28,6 +28,7 @@ import java.net.URI;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.base.Objects;
import com.google.common.collect.ComparisonChain;
/**
* An network-accessible address, usually described by URL, where a service may be accessed. If
@ -50,16 +51,17 @@ public class Endpoint implements Comparable<Endpoint> {
public static class Builder {
protected String id;
protected String versionId;
protected String region;
protected URI publicURL;
protected URI internalURL;
protected String tenantId;
/**
* @see Endpoint#getId()
* @see Endpoint#getVersionId()
*/
public Builder id(String id) {
this.id = checkNotNull(id, "id");
public Builder versionId(String versionId) {
this.versionId = checkNotNull(versionId, "versionId");
return this;
}
@ -79,6 +81,14 @@ public class Endpoint implements Comparable<Endpoint> {
return this;
}
/**
* @see Endpoint#getInternalURL()
*/
public Builder internalURL(URI internalURL) {
this.internalURL = checkNotNull(internalURL, "internalURL");
return this;
}
/**
* @see Endpoint#getTenantId()
*/
@ -88,34 +98,43 @@ public class Endpoint implements Comparable<Endpoint> {
}
public Endpoint build() {
return new Endpoint(id, region, publicURL, tenantId);
return new Endpoint(versionId, region, publicURL, internalURL, tenantId);
}
public Builder fromEndpoint(Endpoint from) {
return id(from.getId()).region(from.getRegion()).publicURL(from.getPublicURL()).tenantId(from.getTenantId());
return versionId(from.getVersionId()).region(from.getRegion()).publicURL(from.getPublicURL()).internalURL(
from.getInternalURL()).tenantId(from.getTenantId());
}
}
protected final String id;
// renamed half-way through
@Deprecated
protected String id;
protected final String versionId;
protected final String region;
protected final URI publicURL;
protected final URI internalURL;
// renamed half-way through
@Deprecated
protected String tenantName;
protected final String tenantId;
protected Endpoint(String id, String region, URI publicURL, @Nullable String tenantId) {
this.id = checkNotNull(id, "id");
protected Endpoint(String versionId, String region, @Nullable URI publicURL, @Nullable URI internalURL,
@Nullable String tenantId) {
this.versionId = checkNotNull(versionId, "versionId");
this.region = checkNotNull(region, "region");
this.publicURL = checkNotNull(publicURL, "publicURL");
this.publicURL = publicURL;
this.internalURL = internalURL;
this.tenantId = tenantId;
}
/**
* When providing an ID, it is assumed that the endpoint exists in the current OpenStack
* When provversionIding an ID, it is assumed that the endpoint exists in the current OpenStack
* deployment
*
* @return the id of the endpoint in the current OpenStack deployment
* @return the versionId of the endpoint in the current OpenStack deployment
*/
public String getId() {
return id;
public String getVersionId() {
return versionId != null ? versionId : id;
}
/**
@ -126,19 +145,27 @@ public class Endpoint implements Comparable<Endpoint> {
}
/**
* @return the service id of the endpoint
* @return the public url of the endpoint
*/
@Nullable
public URI getPublicURL() {
return publicURL;
}
/**
* @return the tenant id of the endpoint or null
* @return the internal url of the endpoint
*/
@Nullable
public URI getInternalURL() {
return internalURL;
}
/**
* @return the tenant versionId of the endpoint or null
*/
@Nullable
public String getTenantId() {
return tenantId;
return tenantId != null ? tenantId : tenantName;
}
@Override
@ -148,8 +175,8 @@ public class Endpoint implements Comparable<Endpoint> {
}
if (object instanceof Endpoint) {
final Endpoint other = Endpoint.class.cast(object);
return equal(id, other.id) && equal(region, other.region) && equal(publicURL, other.publicURL)
&& equal(tenantId, other.tenantId);
return equal(getVersionId(), other.getVersionId()) && equal(region, other.region) && equal(publicURL, other.publicURL)
&& equal(internalURL, other.internalURL) && equal(getTenantId(), other.getTenantId());
} else {
return false;
}
@ -157,22 +184,19 @@ public class Endpoint implements Comparable<Endpoint> {
@Override
public int hashCode() {
return Objects.hashCode(id, region, publicURL, tenantId);
return Objects.hashCode(getVersionId(), region, publicURL, internalURL, getTenantId());
}
@Override
public String toString() {
return toStringHelper("").add("id", id).add("region", region).add("publicURL", publicURL).add("tenantId",
tenantId).toString();
return toStringHelper("").add("versionId", getVersionId()).add("region", region).add("publicURL", publicURL).add("internalURL",
internalURL).add("tenantId", getTenantId()).toString();
}
@Override
public int compareTo(Endpoint that) {
if (that == null)
return 1;
if (this == that)
return 0;
return this.id.compareTo(that.id);
return ComparisonChain.start().compare(this.getTenantId(), that.getTenantId()).compare(this.getVersionId(), that.getVersionId())
.compare(this.region, that.region).result();
}
}

View File

@ -26,6 +26,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.base.Objects;
import com.google.common.collect.ComparisonChain;
/**
* A personality that a user assumes when performing a specific set of operations. A role includes a
@ -99,6 +100,9 @@ public class Role implements Comparable<Role> {
protected final String id;
protected final String name;
protected final String serviceId;
// renamed half-way through
@Deprecated
protected String tenantName;
protected final String tenantId;
protected Role(String id, String name, @Nullable String serviceId, @Nullable String tenantId) {
@ -137,7 +141,7 @@ public class Role implements Comparable<Role> {
*/
@Nullable
public String getTenantId() {
return tenantId;
return tenantId != null ? tenantId : tenantName;
}
@Override
@ -148,7 +152,7 @@ public class Role implements Comparable<Role> {
if (object instanceof Role) {
final Role other = Role.class.cast(object);
return equal(id, other.id) && equal(name, other.name) && equal(serviceId, other.serviceId)
&& equal(tenantId, other.tenantId);
&& equal(getTenantId(), other.getTenantId());
} else {
return false;
}
@ -156,22 +160,18 @@ public class Role implements Comparable<Role> {
@Override
public int hashCode() {
return Objects.hashCode(id, name, serviceId, tenantId);
return Objects.hashCode(id, name, serviceId, getTenantId());
}
@Override
public String toString() {
return toStringHelper("").add("id", id).add("name", name).add("serviceId", serviceId).add("tenantId", tenantId)
return toStringHelper("").add("id", id).add("name", name).add("serviceId", serviceId).add("tenantId", getTenantId())
.toString();
}
@Override
public int compareTo(Role that) {
if (that == null)
return 1;
if (this == that)
return 0;
return this.id.compareTo(that.id);
return ComparisonChain.start().compare(this.id, that.id).result();
}
}

View File

@ -87,7 +87,7 @@ public class Service implements Comparable<Service> {
}
public Builder fromService(Service from) {
return type(from.getId()).name(from.getName()).endpoints(from.getEndpoints());
return type(from.getType()).name(from.getName()).endpoints(from.getEndpoints());
}
}
@ -106,7 +106,7 @@ public class Service implements Comparable<Service> {
*
* @return the type of the service in the current OpenStack deployment
*/
public String getId() {
public String getType() {
return type;
}

View File

@ -0,0 +1,29 @@
/**
* 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.v2_0.functions;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import com.google.common.base.Function;
import com.google.inject.ImplementedBy;
@ImplementedBy(ReturnRegion.class)
public interface EndpointToRegion extends Function<Endpoint, String> {
}

View File

@ -0,0 +1,31 @@
/**
* 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.v2_0.functions;
import java.net.URI;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.inject.ImplementedBy;
@ImplementedBy(PublicURLOrInternalIfNull.class)
public interface EndpointToSupplierURI extends Function<Endpoint, Supplier<URI>> {
}

View File

@ -1,65 +0,0 @@
/**
* 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.v2_0.functions;
import java.net.URI;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.domain.Service;
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 PublicURLFromAccessForService implements Supplier<URI> {
public static interface Factory {
PublicURLFromAccessForService create(String service);
}
private final Supplier<Access> auth;
private final String service;
@Inject
public PublicURLFromAccessForService(Supplier<Access> auth, @Assisted String service) {
this.auth = auth;
this.service = service;
}
@Override
public URI get() {
return Iterables.getOnlyElement(Iterables.find(auth.get().getServiceCatalog(), new Predicate<Service>(){
@Override
public boolean apply(Service input) {
return input.getId().equals(service);
}
}).getEndpoints()).getPublicURL();
}
@Override
public String toString() {
return "getPublicURLForService(" + service + ")";
}
}

View File

@ -0,0 +1,46 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.keystone.v2_0.functions;
import java.net.URI;
import javax.inject.Singleton;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
@Singleton
public class PublicURLOrInternalIfNull implements EndpointToSupplierURI {
// TODO: check accessibility and prioritize private first
@Override
public Supplier<URI> apply(Endpoint input) {
return Suppliers.ofInstance(input.getPublicURL() != null ? input.getPublicURL() : input.getInternalURL());
}
public String toString() {
return "supplyPublicURL()";
}
}

View File

@ -0,0 +1,34 @@
/**
* 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.v2_0.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Singleton;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
@Singleton
public class ReturnRegion implements EndpointToRegion {
@Override
public String apply(Endpoint input) {
return checkNotNull(input.getRegion(), "no region for endpoint %s", input);
}
}

View File

@ -0,0 +1,86 @@
/**
* 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.v2_0.suppliers;
import java.net.URI;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.jclouds.openstack.keystone.v2_0.domain.Service;
import org.jclouds.openstack.keystone.v2_0.functions.EndpointToRegion;
import org.jclouds.openstack.keystone.v2_0.functions.EndpointToSupplierURI;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.inject.assistedinject.Assisted;
@Singleton
public class RegionIdToURIFromAccessForTypeAndVersionSupplier implements RegionIdToURISupplier {
private final Supplier<Access> access;
private final EndpointToSupplierURI endpointToSupplierURI;
private final EndpointToRegion endpointToRegion;
private final String apiType;
private final String apiVersion;
@Inject
public RegionIdToURIFromAccessForTypeAndVersionSupplier(Supplier<Access> access,
EndpointToSupplierURI endpointToSupplierURI, EndpointToRegion endpointToRegion,
@Assisted("apiType") String apiType, @Assisted("apiVersion") String apiVersion) {
this.access = access;
this.endpointToSupplierURI = endpointToSupplierURI;
this.endpointToRegion = endpointToRegion;
this.apiType = apiType;
this.apiVersion = apiVersion;
}
@Override
public Map<String, Supplier<URI>> get() {
Access accessResponse = access.get();
Service service = Iterables.find(accessResponse.getServiceCatalog(), new Predicate<Service>() {
@Override
public boolean apply(Service input) {
return input.getType().equals(apiType);
}
});
Map<String, Endpoint> regionIdToEndpoint = Maps.uniqueIndex(Iterables.filter(service.getEndpoints(),
new Predicate<Endpoint>() {
@Override
public boolean apply(Endpoint input) {
return input.getVersionId().equals(apiVersion);
}
}), endpointToRegion);
return Maps.transformValues(regionIdToEndpoint, endpointToSupplierURI);
}
@Override
public String toString() {
return "regionIdToURIFromAccessForTypeAndVersion(" + apiType + ", " + apiVersion + ")";
}
}

View File

@ -0,0 +1,48 @@
/**
* 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.functions;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import org.jclouds.openstack.keystone.v1_1.domain.Endpoint;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "PublicURLOrInternalIfNullTest")
public class PublicURLOrInternalIfNullTest {
private final PublicURLOrInternalIfNull fn = new PublicURLOrInternalIfNull();
public void testPublicURLNotNullReturnsPublicURL() {
assertEquals(fn.apply(
Endpoint.builder().region("LON").publicURL(
URI.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"))
.v1Default(true).build()).get(), URI
.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"));
}
public void testPublicURLNullReturnsInternalURL() {
assertEquals(fn.apply(Endpoint.builder().internalURL(URI.create("https://192.168.1.1")).v1Default(true).build())
.get(), URI.create("https://192.168.1.1"));
}
}

View File

@ -0,0 +1,52 @@
/**
* 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.functions;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import org.jclouds.openstack.keystone.v1_1.domain.Endpoint;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "RegionFirstPartOfDNSNameOrProviderTest")
public class RegionFirstPartOfDNSNameOrProviderTest {
private final RegionFirstPartOfDNSNameOrProvider fn = new RegionFirstPartOfDNSNameOrProvider("keystone");
public void testRegionNotNullReturnsRegion() {
assertEquals(fn.apply(Endpoint.builder().region("LON").publicURL(
URI.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"))
.v1Default(true).build()), "LON");
}
public void testRegionNullReturnsFirstPartOfHostWhenValid() {
assertEquals(fn.apply(Endpoint.builder().publicURL(
URI.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"))
.v1Default(true).build()), "cdn3");
}
public void testRegionNullReturnsProvioderWhenHostNotValid() {
assertEquals(fn.apply(Endpoint.builder().publicURL(URI.create("https://1.1.1.4")).v1Default(true).build()),
"keystone");
}
}

View File

@ -0,0 +1,75 @@
/**
* 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 java.net.URI;
import javax.inject.Singleton;
import org.jclouds.location.Provider;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
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.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
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 = "RegionIdToURIFromAuthForServiceSupplierTest")
public class RegionIdToURIFromAuthForServiceSupplierTest {
private final RegionIdToURISupplier.Factory factory = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bindConstant().annotatedWith(Provider.class).to("keystone");
install(new FactoryModuleBuilder().implement(RegionIdToURISupplier.class,
RegionIdToURIFromAuthForServiceSupplier.class).build(RegionIdToURISupplier.Factory.class));
}
@SuppressWarnings("unused")
@Provides
@Singleton
public Supplier<Auth> provide() {
return Suppliers.ofInstance(new ParseAuthTest().expected());
}
}).getInstance(RegionIdToURISupplier.Factory.class);
public void testRegionMatches() {
assertEquals(Maps.transformValues(factory.createForApiTypeAndVersion("cloudFilesCDN", "1.0").get(), Suppliers
.<URI> supplierFunction()), ImmutableMap.of("LON", URI
.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953")));
}
public void testTakesFirstPartOfDNSWhenNoRegion() {
assertEquals(Maps.transformValues(factory.createForApiTypeAndVersion("cloudServers", "1.1").get(), Suppliers
.<URI> supplierFunction()), ImmutableMap.of("lon", URI
.create("https://lon.servers.api.rackspacecloud.com/v1.0/10001786")));
}
}

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.openstack.keystone.v2_0.functions;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "PublicURLOrInternalIfNullTest")
public class PublicURLOrInternalIfNullTest {
private final PublicURLOrInternalIfNull fn = new PublicURLOrInternalIfNull();
public void testPublicURLNotNullReturnsPublicURL() {
assertEquals(fn.apply(
Endpoint.builder().region("LON").versionId("1.0").publicURL(
URI.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"))
.build()).get(), URI
.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"));
}
public void testPublicURLNullReturnsInternalURL() {
assertEquals(fn
.apply(
Endpoint.builder().region("lon").versionId("1.0")
.internalURL(URI.create("https://192.168.1.1")).build()).get(), URI
.create("https://192.168.1.1"));
}
}

View File

@ -0,0 +1,53 @@
/**
* 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.v2_0.functions;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ReturnRegionTest")
public class ReturnRegionTest {
private final ReturnRegion fn = new ReturnRegion();
public void testRegionNotNullReturnsRegion() {
assertEquals(
fn.apply(Endpoint.builder().region("LON").versionId("1.0").publicURL(
URI.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"))
.build()), "LON");
}
public void testRegionNullNiceNPE() {
try {
fn.apply(Endpoint.builder().versionId("1.0").publicURL(
URI.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"))
.build());
assert false;
} catch (NullPointerException e) {
assertEquals(e.getMessage(), "region");
}
}
}

View File

@ -17,15 +17,18 @@
* under the License.
*/
package org.jclouds.openstack.keystone.v2_0.internal;
import static java.lang.String.format;
import static org.jclouds.rest.BaseRestClientExpectTest.payloadFromStringWithContentType;
import java.io.IOException;
import java.net.URI;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule;
import org.jclouds.rest.BaseRestClientExpectTest;
import org.jclouds.io.Payload;
import org.jclouds.util.Strings2;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.net.HttpHeaders;
@ -34,13 +37,15 @@ import com.google.common.net.HttpHeaders;
*
* @author Adrian Cole
*/
public class BaseKeystoneRestClientExpectTest<S> extends BaseRestClientExpectTest<S> {
public enum KeystoneFixture {
INSTANCE;
protected static final String tenantId = "12346637803162";
public String getTenantName(){
return "12346637803162";
}
protected static final String username = "user@jclouds.org";
protected static final String password = "Password1234";
protected static final HttpRequest initialAuthWithPasswordCredentials = HttpRequest
public HttpRequest initialAuthWithUsernameAndPassword(String username, String password){
return HttpRequest
.builder()
.method("POST")
.endpoint(URI.create("http://localhost:5000/v2.0/tokens"))
@ -48,12 +53,12 @@ public class BaseKeystoneRestClientExpectTest<S> extends BaseRestClientExpectTes
.payload(
payloadFromStringWithContentType(
format(
"{\"auth\":{\"passwordCredentials\":{\"username\":\"%s\",\"password\":\"%s\"},\"tenantId\":\"%s\"}}",
username, password, tenantId), "application/json")).build();
"{\"auth\":{\"passwordCredentials\":{\"username\":\"%s\",\"password\":\"%s\"},\"tenantName\":\"%s\"}}",
username, password, getTenantName()), "application/json")).build();
}
protected static final String accessKey = "FH6FU8GMZFLKP5BUR2X1";
protected static final String secretKey = "G4QWed0lh5SH7kBrcvOM1cHygKWk81EBt+Hr1dsl";
protected static final HttpRequest initialAuthWithApiAccessKeyCredentials = HttpRequest
public HttpRequest initialAuthWithAccessKeyAndSecretKey(String accessKey, String secretKey){
return HttpRequest
.builder()
.method("POST")
.endpoint(URI.create("http://localhost:5000/v2.0/tokens"))
@ -61,30 +66,27 @@ public class BaseKeystoneRestClientExpectTest<S> extends BaseRestClientExpectTes
.payload(
payloadFromStringWithContentType(
format(
"{\"auth\":{\"apiAccessKeyCredentials\":{\"accessKey\":\"%s\",\"secretKey\":\"%s\"},\"tenantId\":\"%s\"}}",
accessKey, secretKey, tenantId), "application/json")).build();
"{\"auth\":{\"apiAccessKeyCredentials\":{\"accessKey\":\"%s\",\"secretKey\":\"%s\"},\"tenantName\":\"%s\"}}",
accessKey, secretKey, getTenantName()), "application/json")).build();
}
public BaseKeystoneRestClientExpectTest() {
identity = tenantId + ":" + accessKey;
credential = secretKey;
public String getAuthToken(){
return "Auth_4f173437e4b013bee56d1007";
}
public HttpResponse responseWithAccess(){
return HttpResponse.builder().statusCode(200).message("HTTP/1.1 200").payload(
payloadFromResourceWithContentType("/keystoneAuthResponse.json", "application/json")).build();
}
protected String authToken = "Auth_4f173437e4b013bee56d1007";
protected HttpResponse responseWithAccess = HttpResponse.builder().statusCode(200).message("HTTP/1.1 200").payload(
payloadFromResourceWithContentType("/keystoneAuthResponse.json", "application/json")).build();
/**
* in case you need to override anything
*/
public static class TestKeystoneAuthenticationModule extends KeystoneAuthenticationModule {
@Override
protected void configure() {
super.configure();
public Payload payloadFromResourceWithContentType(String resource, String contentType) {
try {
return payloadFromStringWithContentType(Strings2.toStringAndClose(getClass().getResourceAsStream(resource)),
contentType);
} catch (IOException e) {
throw Throwables.propagate(e);
}
}
}

View File

@ -63,23 +63,28 @@ public class ParseAccessTest extends BaseItemParserTest<Access> {
Role.builder().id("00000000004004").serviceId("100").name("domainuser").build(),
Role.builder().id("00000000004016").serviceId("120").name("netadmin")
.tenantId("40806637803162").build()).build()).serviceCatalog(
Service.builder().name("Object Storage").type("object-store").endpoints(
Endpoint.builder().tenantId("40806637803162").publicURL(
URI.create("https://objects.jclouds.org/v1.0/40806637803162"))
.region("region-a.geo-1").id("1.0").build()).build(),
.region("region-a.geo-1").versionId("1.0").build()).build(),
Service.builder().name("Identity").type("identity").endpoints(
Endpoint.builder().publicURL(URI.create("https://csnode.jclouds.org/v2.0/")).region(
"region-a.geo-1").id("2.0").build()).build(),
Service.builder()
"region-a.geo-1").versionId("2.0").build()).build(),
.name("Image Management").type("image").endpoints(
Service.builder().name("Image Management").type("image").endpoints(
Endpoint.builder().tenantId("40806637803162").publicURL(
URI.create("https://glance.jclouds.org:9292/v1.0")).region("az-1.region-a.geo-1").id(
"1.0").build()).build(),
Service.builder().name("Compute").type("compute").endpoints(
Endpoint.builder().tenantId("40806637803162").publicURL(
URI.create("http://compute-1.jclouds.org:8774/v1.1/40806637803162")).region(
"az-1.region-a.geo-1").id("1.1").build()).build()).build();
URI.create("https://glance.jclouds.org:9292/v1.0")).region("az-1.region-a.geo-1")
.versionId("1.0").build()).build(),
Service.builder().name("Cloud Servers").type("compute").endpoints(
Endpoint.builder().tenantId("1").publicURL(URI.create("https://compute.north.host/v1/1234"))
.internalURL(URI.create("https://compute.north.host/v1/1234")).region("North")
.versionId("1.0").build(),
Endpoint.builder().tenantId("2").publicURL(URI.create("https://compute.north.host/v1.1/3456"))
.internalURL(URI.create("https://compute.north.host/v1.1/3456")).region("North")
.versionId("1.1").build()).build()).build();
}

View File

@ -0,0 +1,69 @@
/**
* 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.v2_0.suppliers;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import javax.inject.Singleton;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.parse.ParseAccessTest;
import org.testng.annotations.Test;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
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 = "RegionIdToURIFromAccessForTypeAndVersionSupplierTest")
public class RegionIdToURIFromAccessForTypeAndVersionSupplierTest {
private final RegionIdToURISupplier.Factory factory = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
install(new FactoryModuleBuilder().implement(RegionIdToURISupplier.class,
RegionIdToURIFromAccessForTypeAndVersionSupplier.class).build(RegionIdToURISupplier.Factory.class));
}
@SuppressWarnings("unused")
@Provides
@Singleton
public Supplier<Access> provide() {
return Suppliers.ofInstance(new ParseAccessTest().expected());
}
}).getInstance(RegionIdToURISupplier.Factory.class);
public void testRegionMatches() {
assertEquals(Maps.transformValues(factory.createForApiTypeAndVersion("compute", "1.0").get(), Suppliers
.<URI> supplierFunction()), ImmutableMap.of("North", URI.create("https://compute.north.host/v1/1234")));
assertEquals(Maps.transformValues(factory.createForApiTypeAndVersion("compute", "1.1").get(), Suppliers
.<URI> supplierFunction()), ImmutableMap.of("North", URI.create("https://compute.north.host/v1.1/3456")));
}
}

View File

@ -16,13 +16,13 @@
"id": "00000000004022",
"serviceId": "110",
"name": "Admin",
"tenantId": "40806637803162"
"tenantName": "40806637803162"
},
{
"id": "00000000004024",
"serviceId": "140",
"name": "user",
"tenantId": "40806637803162"
"tenantName": "40806637803162"
},
{
"id": "00000000004004",
@ -33,7 +33,7 @@
"id": "00000000004016",
"serviceId": "120",
"name": "netadmin",
"tenantId": "40806637803162"
"tenantName": "40806637803162"
}
]
},
@ -43,7 +43,7 @@
"type": "object-store",
"endpoints": [
{
"tenantId": "40806637803162",
"tenantName": "40806637803162",
"adminURL": "https://objects.jclouds.org/v1.0/",
"publicURL": "https://objects.jclouds.org/v1.0/40806637803162",
"region": "region-a.geo-1",
@ -68,7 +68,7 @@
"type": "image",
"endpoints": [
{
"tenantId": "40806637803162",
"tenantName": "40806637803162",
"publicURL": "https://glance.jclouds.org:9292/v1.0",
"region": "az-1.region-a.geo-1",
"id": "1.0"
@ -76,17 +76,28 @@
]
},
{
"name": "Compute",
"type": "compute",
"endpoints": [
"name":"Cloud Servers",
"type":"compute",
"endpoints":[{
"tenantId":"1",
"publicURL":"https://compute.north.host/v1/1234",
"internalURL":"https://compute.north.host/v1/1234",
"region":"North",
"versionId":"1.0",
"versionInfo":"https://compute.north.host/v1.0/",
"versionList":"https://compute.north.host/"
},
{
"tenantId": "40806637803162",
"publicURL": "http://compute-1.jclouds.org:8774/v1.1/40806637803162",
"region": "az-1.region-a.geo-1",
"id": "1.1",
"list": "http://compute-1.jclouds.org:8774"
"tenantId":"2",
"publicURL":"https://compute.north.host/v1.1/3456",
"internalURL":"https://compute.north.host/v1.1/3456",
"region":"North",
"versionId":"1.1",
"versionInfo":"https://compute.north.host/v1.1/",
"versionList":"https://compute.north.host/"
}
]
],
"endpoints_links":[]
}
]
}

View File

@ -25,6 +25,7 @@ import org.jclouds.location.suppliers.fromconfig.RegionIdToURIFromConfigurationO
import com.google.common.base.Supplier;
import com.google.inject.ImplementedBy;
import com.google.inject.assistedinject.Assisted;
/**
*
@ -33,5 +34,18 @@ import com.google.inject.ImplementedBy;
*/
@ImplementedBy(RegionIdToURIFromConfigurationOrDefaultToProvider.class)
public interface RegionIdToURISupplier extends Supplier<Map<String, Supplier<URI>>> {
static interface Factory {
/**
*
* @param apiType
* type of the api, according to the provider. ex. {@code compute} {@code
* object-store}
* @param apiVersion
* version of the api
* @return regions mapped to default uri
*/
RegionIdToURISupplier createForApiTypeAndVersion(@Assisted("apiType") String apiType,
@Assisted("apiVersion") String apiVersion);
}
}

View File

@ -0,0 +1,50 @@
/**
* 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.location.suppliers.derived;
import java.net.URI;
import java.util.Map;
import java.util.Set;
import javax.inject.Singleton;
import org.jclouds.location.Region;
import org.jclouds.location.suppliers.RegionIdsSupplier;
import com.google.common.base.Supplier;
import com.google.inject.Inject;
/**
* as opposed to via properties, lets look up regions via api, as they are more likely to change
*/
@Singleton
public class RegionIdsFromRegionIdToURIKeySet implements RegionIdsSupplier {
private final Supplier<Map<String, Supplier<URI>>> regionIdToURISupplier;
@Inject
protected RegionIdsFromRegionIdToURIKeySet(@Region Supplier<Map<String, Supplier<URI>>> regionIdToURISupplier) {
this.regionIdToURISupplier = regionIdToURISupplier;
}
@Override
public Set<String> get() {
return regionIdToURISupplier.get().keySet();
}
}

View File

@ -0,0 +1,57 @@
/**
* 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.location.suppliers.derived;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.location.Zone;
import org.jclouds.location.suppliers.ZoneIdsSupplier;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
* as opposed to via properties, lets look up zones via api, as they are more likely to change
*/
@Singleton
public class ZoneIdsFromRegionIdToZoneIdsValues implements ZoneIdsSupplier {
private final Supplier<Map<String, Supplier<Set<String>>>> regionIdToZoneIdsSupplier;
@Inject
protected ZoneIdsFromRegionIdToZoneIdsValues(
@Zone Supplier<Map<String, Supplier<Set<String>>>> regionIdToZoneIdsSupplier) {
this.regionIdToZoneIdsSupplier = regionIdToZoneIdsSupplier;
}
@Override
public Set<String> get() {
Collection<Supplier<Set<String>>> zones = regionIdToZoneIdsSupplier.get().values();
return ImmutableSet.copyOf(Iterables.concat(Iterables.transform(zones, Suppliers
.<Set<String>> supplierFunction())));
}
}

View File

@ -18,10 +18,10 @@
*/
package org.jclouds.rest.internal;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.NoSuchElementException;
import java.util.concurrent.ExecutionException;
@ -45,38 +45,38 @@ import org.jclouds.util.Throwables2;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.Binding;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provides;
import com.google.inject.ProvisionException;
import com.google.inject.TypeLiteral;
import com.google.inject.util.Types;
/**
* Generates RESTful clients from appropriately annotated interfaces.
* <p/>
* Particularly, this code delegates calls to other things.
* <ol>
* <li>if the method has a {@link Provides} annotation, it responds via a
* {@link Injector} lookup</li>
* <li>if the method has a {@link Delegate} annotation, it responds with an
* instance of interface set in returnVal, adding the current JAXrs annotations
* to whatever are on that class.</li>
* <li>if the method has a {@link Provides} annotation, it responds via a {@link Injector} lookup</li>
* <li>if the method has a {@link Delegate} annotation, it responds with an instance of interface
* set in returnVal, adding the current JAXrs annotations to whatever are on that class.</li>
* <ul>
* <li>ex. if the method with {@link Delegate} has a {@link Path} annotation,
* and the returnval interface also has {@link Path}, these values are combined.
* </li>
* <li>ex. if the method with {@link Delegate} has a {@link Path} annotation, and the returnval
* interface also has {@link Path}, these values are combined.</li>
* </ul>
* <li>if {@link RestAnnotationProcessor#delegationMap} contains a mapping for
* this, and the returnVal is properly assigned as a {@link ListenableFuture},
* it responds with an http implementation.</li>
* <li>otherwise a RuntimeException is thrown with a message including:
* {@code method is intended solely to set constants}</li>
* <li>if {@link RestAnnotationProcessor#delegationMap} contains a mapping for this, and the
* returnVal is properly assigned as a {@link ListenableFuture}, it responds with an http
* implementation.</li>
* <li>otherwise a RuntimeException is thrown with a message including: {@code method is intended
* solely to set constants}</li>
* </ol>
*
* @author Adrian Cole
@ -133,7 +133,8 @@ public class AsyncRestClientProxy<T> implements InvocationHandler {
} else if (isRestCall(method)) {
return createListenableFutureForHttpRequestMappedToMethodAndArgs(method, args);
} else {
throw new RuntimeException(String.format("Method is not annotated as either http or provider method: %s", method));
throw new RuntimeException(String.format("Method is not annotated as either http or provider method: %s",
method));
}
}
@ -148,11 +149,18 @@ public class AsyncRestClientProxy<T> implements InvocationHandler {
public Object lookupValueFromGuice(Method method) {
try {
Type genericReturnType = method.getGenericReturnType();
try {
Annotation qualifier = Iterables.find(ImmutableList.copyOf(method.getAnnotations()), isQualifierPresent);
return injector.getInstance(Key.get(method.getGenericReturnType(), qualifier));
Binding<?> binding = injector.getExistingBinding(Key.get(genericReturnType, qualifier));
if (binding != null)
return binding.getProvider().get();
// try looking via supplier
return Supplier.class.cast(
injector.getInstance(Key.get(Types.newParameterizedType(Supplier.class, genericReturnType),
qualifier))).get();
} catch (NoSuchElementException e) {
return injector.getInstance(Key.get(method.getGenericReturnType()));
return injector.getInstance(Key.get(genericReturnType));
}
} catch (ProvisionException e) {
AuthorizationException aex = Throwables2.getFirstThrowableOfType(e, AuthorizationException.class);
@ -163,7 +171,8 @@ public class AsyncRestClientProxy<T> implements InvocationHandler {
}
@SuppressWarnings( { "unchecked", "rawtypes" })
private ListenableFuture<?> createListenableFutureForHttpRequestMappedToMethodAndArgs(Method method, Object[] args) throws ExecutionException {
private ListenableFuture<?> createListenableFutureForHttpRequestMappedToMethodAndArgs(Method method, Object[] args)
throws ExecutionException {
method = annotationProcessor.getDelegateOrNull(method);
logger.trace("Converting %s.%s", declaring.getSimpleName(), method.getName());
Function<Exception, ?> exceptionParser = annotationProcessor

View File

@ -734,7 +734,7 @@ public class RestAnnotationProcessor<T> {
String.format("endpoint for [%s] not configured for %s", args[index], method));
return returnVal;
} catch (NullPointerException e) {
throw new IllegalArgumentException(String.format("argument at index %d on method %s", index, method), e);
throw new IllegalArgumentException(String.format("argument at index %d on method %s was null", index, method), e);
}
} else {
SortedSet<Integer> keys = newTreeSet(map.keySet());

View File

@ -23,6 +23,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import com.google.common.annotations.VisibleForTesting;
@ -30,6 +31,7 @@ import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.Iterables;
import com.google.common.io.OutputSupplier;
/**
@ -38,6 +40,21 @@ import com.google.common.io.OutputSupplier;
*/
public class Suppliers2 {
public static <K, V> Supplier<V> getLastValueInMap(Supplier<Map<K, Supplier<V>>> input) {
return Suppliers.compose(new Function<Map<K, Supplier<V>>, V>() {
@Override
public V apply(Map<K, Supplier<V>> input) {
return Iterables.getLast(input.values()).get();
}
@Override
public String toString() {
return "getLastValueInMap()";
}
}, input);
}
public static <X> Function<X, Supplier<X>> ofInstanceFunction() {
return new Function<X, Supplier<X>>(){

View File

@ -202,6 +202,11 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@Timeout(duration = 10, timeUnit = TimeUnit.NANOSECONDS)
public static interface Caller {
// tests that we can pull from suppliers
@Provides
@Localhost2
URI getURI();
@Delegate
public Callee getCallee();
@ -216,6 +221,9 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
}
public static interface AsyncCaller {
@Provides
@Localhost2
URI getURI();
@Delegate
public AsyncCallee getCallee();
@ -267,6 +275,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
}
child.getInstance(Caller.class).getCallee().onePath("foo");
child.getInstance(Caller.class).getCallee().onePath("foo");
}
@ -292,6 +301,8 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
child.getInstance(AsyncCaller.class).getCallee(URI.create("http://howdyboys")).onePath("foo").get();
assertEquals(child.getInstance(AsyncCaller.class).getURI(), URI.create("http://localhost:1111"));
}
public void testDelegateIsLazyLoadedAndRequestIncludesEndpointVersionAndPath() throws InterruptedException, ExecutionException {
@ -313,7 +324,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
}
child.getInstance(Caller.class).getCallee(URI.create("http://howdyboys")).onePath("foo");
assertEquals(child.getInstance(Caller.class).getURI(), URI.create("http://localhost:1111"));
}

View File

@ -28,6 +28,7 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
@ -37,9 +38,24 @@ import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
public class Suppliers2Test {
@Test
public void testGetLastValueInMap() {
assertEquals(Suppliers2
.<String, String> getLastValueInMap(
Suppliers.<Map<String, Supplier<String>>> ofInstance(ImmutableMap.of("foo", Suppliers
.ofInstance("bar")))).get(), "bar");
}
@Test
public void testOfInstanceFunction() {
assertEquals(Suppliers2.ofInstanceFunction().apply("foo").get(), "foo");
}
@Test
public void testMemoizeKeepsValueForFullDurationWhenDelegateCallIsSlow() {
final long SLEEP_TIME = 250;

View File

@ -37,7 +37,7 @@
<!-- keystone endpoint -->
<test.openstack-nova.endpoint>http://localhost:5000</test.openstack-nova.endpoint>
<!-- keystone version -->
<test.openstack-nova.api-version>2.0</test.openstack-nova.api-version>
<test.openstack-nova.api-version>1.1</test.openstack-nova.api-version>
<test.openstack-nova.build-version></test.openstack-nova.build-version>
<test.openstack-nova.identity>FIXME_IDENTITY</test.openstack-nova.identity>
<test.openstack-nova.credential>FIXME_CREDENTIALS</test.openstack-nova.credential>

View File

@ -18,8 +18,16 @@
*/
package org.jclouds.openstack.nova.v1_1;
import java.util.Set;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.Region;
import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull;
import org.jclouds.openstack.nova.v1_1.features.ServerAsyncClient;
import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam;
import com.google.inject.Provides;
/**
* Provides asynchronous access to Nova via their REST API.
@ -31,10 +39,19 @@ import org.jclouds.rest.annotations.Delegate;
*/
public interface NovaAsyncClient {
/**
*
* @return the region codes configured
*/
@Provides
@Region
Set<String> getConfiguredRegions();
/**
* Provides asynchronous access to Server features.
*/
@Delegate
ServerAsyncClient getServerClient();
ServerAsyncClient getServerClientForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
}

View File

@ -18,11 +18,18 @@
*/
package org.jclouds.openstack.nova.v1_1;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.Region;
import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull;
import org.jclouds.openstack.nova.v1_1.features.ServerClient;
import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam;
import com.google.inject.Provides;
/**
* Provides synchronous access to Nova.
@ -34,11 +41,19 @@ import org.jclouds.rest.annotations.Delegate;
*/
@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
public interface NovaClient {
/**
*
* @return the region codes configured
*/
@Provides
@Region
Set<String> getConfiguredRegions();
/**
* Provides synchronous access to Server features.
*/
@Delegate
ServerClient getServerClient();
ServerClient getServerClientForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
}

View File

@ -24,6 +24,8 @@ import static org.jclouds.Constants.PROPERTY_ENDPOINT;
import java.util.Properties;
import org.jclouds.PropertiesBuilder;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
import org.jclouds.openstack.services.ServiceType;
/**
* Builds properties used in Nova Clients
@ -34,9 +36,11 @@ public class NovaPropertiesBuilder extends PropertiesBuilder {
@Override
protected Properties defaultProperties() {
Properties properties = super.defaultProperties();
// TODO: keystone
properties.setProperty(PROPERTY_ENDPOINT, "http://localhost:5000");
properties.setProperty(PROPERTY_API_VERSION, "2.0");
properties.setProperty(KeystoneProperties.SERVICE_TYPE, ServiceType.COMPUTE);
// TODO: this doesn't actually do anything yet.
properties.setProperty(KeystoneProperties.VERSION, "2.0");
properties.setProperty(PROPERTY_API_VERSION, "1.1");
return properties;
}

View File

@ -18,31 +18,23 @@
*/
package org.jclouds.openstack.nova.v1_1.config;
import java.net.URI;
import java.util.Map;
import javax.inject.Singleton;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule;
import org.jclouds.openstack.keystone.v2_0.functions.PublicURLFromAccessForService;
import org.jclouds.openstack.nova.v1_1.NovaAsyncClient;
import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.features.ServerAsyncClient;
import org.jclouds.openstack.nova.v1_1.features.ServerClient;
import org.jclouds.openstack.nova.v1_1.handlers.NovaErrorHandler;
import org.jclouds.openstack.services.Compute;
import org.jclouds.openstack.services.ServiceType;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.config.RestClientModule;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Provides;
/**
* Configures the Nova connection.
@ -57,35 +49,29 @@ public class NovaRestClientModule extends RestClientModule<NovaClient, NovaAsync
.put(ServerClient.class, ServerAsyncClient.class)//
.build();
private final KeystoneAuthenticationModule authModule;
public NovaRestClientModule() {
this(new KeystoneAuthenticationModule());
}
public NovaRestClientModule(KeystoneAuthenticationModule authModule) {
super(NovaClient.class, NovaAsyncClient.class, DELEGATE_MAP);
this.authModule = authModule;
}
@Override
protected void configure() {
install(authModule);
install(new NovaParserModule());
super.configure();
}
@Override
protected void installLocations() {
super.installLocations();
// TODO: select this from KeystoneProperties.VERSION; note you select from a guice provided
// property, so it will have to come from somewhere else, maybe we move this to the the
// ContextBuilder
install(new KeystoneAuthenticationModule());
}
@Override
protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(NovaErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(NovaErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(NovaErrorHandler.class);
}
@Provides
@Singleton
@Compute
protected Supplier<URI> provideServerUrl(PublicURLFromAccessForService.Factory factory) {
return factory.create(ServiceType.COMPUTE);
}
}

View File

@ -29,8 +29,6 @@ import javax.ws.rs.core.MediaType;
import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.services.Compute;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson;
@ -51,7 +49,6 @@ import com.google.common.util.concurrent.ListenableFuture;
*/
@SkipEncoding({ '/', '=' })
@RequestFilters(AuthenticateRequest.class)
@Endpoint(Compute.class)
public interface ServerAsyncClient {
/**

View File

@ -25,12 +25,13 @@ import java.util.Properties;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.nova.v1_1.features.ServerClient;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaRestClientExpectTest;
import org.jclouds.openstack.nova.v1_1.parse.ParseServerListTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
/**
*
@ -40,12 +41,6 @@ import com.google.common.collect.ImmutableMultimap;
@Test(groups = "unit", testName = "PasswordAuthenticationExpectTest")
public class PasswordAuthenticationExpectTest extends BaseNovaRestClientExpectTest {
public PasswordAuthenticationExpectTest() {
provider = "openstack-nova";
identity = tenantId + ":" + username;
credential = password;
}
/**
* this reflects the properties that a user would pass to createContext
*/
@ -58,17 +53,19 @@ public class PasswordAuthenticationExpectTest extends BaseNovaRestClientExpectTe
public void testListServersWhenResponseIs2xx() throws Exception {
HttpRequest listServers = HttpRequest.builder().method("GET").endpoint(
URI.create("http://compute-1.jclouds.org:8774/v1.1/40806637803162/servers")).headers(
URI.create("https://compute.north.host/v1.1/3456/servers")).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build()).build();
HttpResponse listServersResponse = HttpResponse.builder().statusCode(200).payload(
payloadFromResource("/server_list.json")).build();
ServerClient clientWhenServersExist = requestsSendResponses(initialAuthWithPasswordCredentials,
responseWithAccess, listServers, listServersResponse).getServerClient();
NovaClient clientWhenServersExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, listServers, listServersResponse);
assertEquals(clientWhenServersExist.listServers().toString(), new ParseServerListTest().expected().toString());
assertEquals(clientWhenServersExist.getConfiguredRegions(), ImmutableSet.of("North"));
assertEquals(clientWhenServersExist.getServerClientForRegion("North").listServers().toString(), new ParseServerListTest().expected().toString());
}
}

View File

@ -7,12 +7,14 @@ import java.net.URI;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaRestClientExpectTest;
import org.jclouds.openstack.nova.v1_1.parse.ParseServerListTest;
import org.jclouds.openstack.nova.v1_1.parse.ParseServerTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
/**
* Tests annotation parsing of {@code ServerAsyncClient}
@ -22,53 +24,53 @@ import com.google.common.collect.ImmutableMultimap;
@Test(groups = "unit", testName = "ServerAsyncClientTest")
public class ServerClientExpectTest extends BaseNovaRestClientExpectTest {
public ServerClientExpectTest() {
provider = "openstack-nova";
}
public void testListServersWhenResponseIs2xx() throws Exception {
HttpRequest listServers = HttpRequest.builder().method("GET").endpoint(
URI.create("http://compute-1.jclouds.org:8774/v1.1/40806637803162/servers")).headers(
URI.create("https://compute.north.host/v1.1/3456/servers")).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build()).build();
HttpResponse listServersResponse = HttpResponse.builder().statusCode(200).payload(
payloadFromResource("/server_list.json")).build();
ServerClient clientWhenServersExist = requestsSendResponses(initialAuthWithApiAccessKeyCredentials,
responseWithAccess, listServers, listServersResponse).getServerClient();
NovaClient clientWhenServersExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey,
responseWithKeystoneAccess, listServers, listServersResponse);
assertEquals(clientWhenServersExist.listServers().toString(), new ParseServerListTest().expected().toString());
assertEquals(clientWhenServersExist.getConfiguredRegions(), ImmutableSet.of("North"));
assertEquals(clientWhenServersExist.getServerClientForRegion("North").listServers().toString(),
new ParseServerListTest().expected().toString());
}
public void testListServersWhenReponseIs404IsEmpty() throws Exception {
HttpRequest listServers = HttpRequest.builder().method("GET").endpoint(
URI.create("http://compute-1.jclouds.org:8774/v1.1/40806637803162/servers")).headers(
URI.create("https://compute.north.host/v1.1/3456/servers")).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build()).build();
HttpResponse listServersResponse = HttpResponse.builder().statusCode(404).build();
ServerClient clientWhenServersExist = requestsSendResponses(initialAuthWithApiAccessKeyCredentials,
responseWithAccess, listServers, listServersResponse).getServerClient();
NovaClient clientWhenNoServersExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey,
responseWithKeystoneAccess, listServers, listServersResponse);
assertTrue(clientWhenServersExist.listServers().isEmpty());
assertTrue(clientWhenNoServersExist.getServerClientForRegion("North").listServers().isEmpty());
}
// TODO: gson deserializer for Multimap
public void testGetServerWhenResponseIs2xx() throws Exception {
HttpRequest listServers = HttpRequest.builder().method("GET").endpoint(
URI.create("http://compute-1.jclouds.org:8774/v1.1/40806637803162/servers/foo")).headers(
URI.create("https://compute.north.host/v1.1/3456/servers/foo")).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build()).build();
HttpResponse listServersResponse = HttpResponse.builder().statusCode(200).payload(
payloadFromResource("/server_details.json")).build();
ServerClient clientWhenServersExist = requestsSendResponses(initialAuthWithApiAccessKeyCredentials,
responseWithAccess, listServers, listServersResponse).getServerClient();
NovaClient clientWhenServersExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey,
responseWithKeystoneAccess, listServers, listServersResponse);
assertEquals(clientWhenServersExist.getServer("foo").toString(), new ParseServerTest().expected().toString());
assertEquals(clientWhenServersExist.getServerClientForRegion("North").getServer("foo").toString(),
new ParseServerTest().expected().toString());
}
}

View File

@ -26,7 +26,6 @@ import java.util.Set;
import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientLiveTest;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
/**
@ -37,25 +36,20 @@ import org.testng.annotations.Test;
@Test(groups = "live", testName = "ServerClientLiveTest")
public class ServerClientLiveTest extends BaseNovaClientLiveTest {
@BeforeGroups(groups = { "live" })
public void setupClient() {
super.setupClient();
client = context.getApi().getServerClient();
}
private ServerClient client;
@Test
public void testListServersInDetail() throws Exception {
Set<Resource> response = client.listServers();
assert null != response;
assertTrue(response.size() >= 0);
for (Resource server : response) {
Server newDetails = client.getServer(server.getId());
assertEquals(newDetails.getId(), server.getId());
assertEquals(newDetails.getName(), server.getName());
assertEquals(newDetails.getLinks(), server.getLinks());
checkServer(newDetails);
for (String regionId : context.getApi().getConfiguredRegions()) {
ServerClient client = context.getApi().getServerClientForRegion(regionId);
Set<Resource> response = client.listServers();
assert null != response;
assertTrue(response.size() >= 0);
for (Resource server : response) {
Server newDetails = client.getServer(server.getId());
assertEquals(newDetails.getId(), server.getId());
assertEquals(newDetails.getName(), server.getName());
assertEquals(newDetails.getLinks(), server.getLinks());
checkServer(newDetails);
}
}
}

View File

@ -18,36 +18,32 @@
*/
package org.jclouds.openstack.nova.v1_1.internal;
import org.jclouds.http.RequiresHttp;
import org.jclouds.openstack.keystone.v2_0.internal.BaseKeystoneRestClientExpectTest;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.keystone.v2_0.internal.KeystoneFixture;
import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.config.NovaRestClientModule;
import org.jclouds.rest.ConfiguresRestClient;
import com.google.inject.Module;
import org.jclouds.rest.BaseRestClientExpectTest;
/**
* Base class for writing KeyStone Rest Client Expect tests
*
* @author Adrian Cole
*/
public class BaseNovaRestClientExpectTest extends BaseKeystoneRestClientExpectTest<NovaClient> {
public class BaseNovaRestClientExpectTest extends BaseRestClientExpectTest<NovaClient> {
protected HttpRequest keystoneAuthWithUsernameAndPassword;
protected HttpRequest keystoneAuthWithAccessKeyAndSecretKey;
protected String authToken;
protected HttpResponse responseWithKeystoneAccess;
public BaseNovaRestClientExpectTest() {
provider = "openstack-nova";
keystoneAuthWithUsernameAndPassword = KeystoneFixture.INSTANCE.initialAuthWithUsernameAndPassword(identity,
credential);
keystoneAuthWithAccessKeyAndSecretKey = KeystoneFixture.INSTANCE.initialAuthWithAccessKeyAndSecretKey(identity,
credential);
authToken = KeystoneFixture.INSTANCE.getAuthToken();
responseWithKeystoneAccess = KeystoneFixture.INSTANCE.responseWithAccess();
// now, createContext arg will need tenant prefix
identity = KeystoneFixture.INSTANCE.getTenantName() + ":" + identity;
}
@Override
protected Module createModule() {
return new TestNovaRestClientModule();
}
@ConfiguresRestClient
@RequiresHttp
protected static class TestNovaRestClientModule extends NovaRestClientModule {
private TestNovaRestClientModule() {
super(new TestKeystoneAuthenticationModule());
}
}
}

View File

@ -37,17 +37,17 @@ import com.google.common.base.Function;
*/
@Singleton
public class OSTemplateToImage implements Function<OSTemplate, Image> {
private final Function<String, OsFamilyVersion64Bit> imageParser;
private final Function<String, OsFamilyVersion64Bit> osParser;
@Inject
public OSTemplateToImage(Function<String, OsFamilyVersion64Bit> imageParser) {
this.imageParser = imageParser;
public OSTemplateToImage(Function<String, OsFamilyVersion64Bit> osParser) {
this.osParser = osParser;
}
@Override
public Image apply(OSTemplate template) {
checkNotNull(template, "template");
OsFamilyVersion64Bit parsed = imageParser.apply(template.getName());
OsFamilyVersion64Bit parsed = osParser.apply(template.getName());
Builder builder = OperatingSystem.builder();
builder.name(template.getName()).description(template.getName()).is64Bit(parsed.is64Bit).version(parsed.version)
.family(parsed.family);