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; package org.jclouds.cloudfiles.config;
import static org.jclouds.util.Suppliers2.getLastValueInMap;
import java.net.URI; import java.net.URI;
@ -27,22 +28,21 @@ import org.jclouds.cloudfiles.CDNManagement;
import org.jclouds.cloudfiles.CloudFilesAsyncClient; import org.jclouds.cloudfiles.CloudFilesAsyncClient;
import org.jclouds.cloudfiles.CloudFilesClient; import org.jclouds.cloudfiles.CloudFilesClient;
import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.RequiresHttp; import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError; import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection; import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError; import org.jclouds.http.annotation.ServerError;
import org.jclouds.json.config.GsonModule.DateAdapter; import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter; 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.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.CommonSwiftAsyncClient;
import org.jclouds.openstack.swift.CommonSwiftClient; import org.jclouds.openstack.swift.CommonSwiftClient;
import org.jclouds.openstack.swift.Storage; import org.jclouds.openstack.swift.Storage;
import org.jclouds.openstack.swift.config.SwiftObjectModule; import org.jclouds.openstack.swift.config.SwiftObjectModule;
import org.jclouds.openstack.swift.handlers.ParseSwiftErrorFromHttpResponse; import org.jclouds.openstack.swift.handlers.ParseSwiftErrorFromHttpResponse;
import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.annotations.ApiVersion;
import org.jclouds.rest.config.RestClientModule; import org.jclouds.rest.config.RestClientModule;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
@ -55,15 +55,9 @@ import com.google.inject.Provides;
@ConfiguresRestClient @ConfiguresRestClient
@RequiresHttp @RequiresHttp
public class CloudFilesRestClientModule extends RestClientModule<CloudFilesClient, CloudFilesAsyncClient> { 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() { public CloudFilesRestClientModule() {
this(new AuthenticationServiceModule()); super(CloudFilesClient.class, CloudFilesAsyncClient.class);
} }
@Provides @Provides
@ -78,23 +72,8 @@ public class CloudFilesRestClientModule extends RestClientModule<CloudFilesClien
return in; 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 @Override
protected void configure() { protected void configure() {
install(module);
install(new SwiftObjectModule()); install(new SwiftObjectModule());
bind(DateAdapter.class).to(Iso8601DateAdapter.class); bind(DateAdapter.class).to(Iso8601DateAdapter.class);
super.configure(); super.configure();
@ -108,9 +87,23 @@ public class CloudFilesRestClientModule extends RestClientModule<CloudFilesClien
} }
@Override @Override
protected void bindRetryHandlers() { protected void installLocations() {
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(RetryOnRenew.class); 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; package org.jclouds.cloudloadbalancers.config;
import static org.jclouds.util.Suppliers2.getLastValueInMap;
import java.net.URI; import java.net.URI;
import java.util.Map; import java.util.Map;
@ -35,28 +37,26 @@ import org.jclouds.cloudloadbalancers.handlers.ParseCloudLoadBalancersErrorFromH
import org.jclouds.cloudloadbalancers.location.RegionUrisFromPropertiesAndAccountIDPathSuffix; import org.jclouds.cloudloadbalancers.location.RegionUrisFromPropertiesAndAccountIDPathSuffix;
import org.jclouds.cloudloadbalancers.reference.RackspaceConstants; import org.jclouds.cloudloadbalancers.reference.RackspaceConstants;
import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.RequiresHttp; import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError; import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection; import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError; import org.jclouds.http.annotation.ServerError;
import org.jclouds.json.config.GsonModule.DateAdapter; import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter; 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.location.suppliers.RegionIdToURISupplier;
import org.jclouds.openstack.keystone.v1_1.config.AuthenticationServiceModule; 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.ConfiguresRestClient;
import org.jclouds.rest.annotations.ApiVersion;
import org.jclouds.rest.config.RestClientModule; import org.jclouds.rest.config.RestClientModule;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.inject.AbstractModule;
import com.google.inject.Provides; import com.google.inject.Provides;
import com.google.inject.Scopes; import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder; import com.google.inject.assistedinject.FactoryModuleBuilder;
/** /**
@ -67,75 +67,65 @@ import com.google.inject.assistedinject.FactoryModuleBuilder;
@RequiresHttp @RequiresHttp
@ConfiguresRestClient @ConfiguresRestClient
public class CloudLoadBalancersRestClientModule extends public class CloudLoadBalancersRestClientModule extends
RestClientModule<CloudLoadBalancersClient, CloudLoadBalancersAsyncClient> { RestClientModule<CloudLoadBalancersClient, CloudLoadBalancersAsyncClient> {
public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()// public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()//
.put(LoadBalancerClient.class, LoadBalancerAsyncClient.class)// .put(LoadBalancerClient.class, LoadBalancerAsyncClient.class)//
.put(NodeClient.class, NodeAsyncClient.class)// .put(NodeClient.class, NodeAsyncClient.class)//
.build(); .build();
private final AuthenticationServiceModule module;
public CloudLoadBalancersRestClientModule(AuthenticationServiceModule module) {
super(CloudLoadBalancersClient.class, CloudLoadBalancersAsyncClient.class, DELEGATE_MAP);
this.module = module;
}
public CloudLoadBalancersRestClientModule() { public CloudLoadBalancersRestClientModule() {
this(new AuthenticationServiceModule()); super(CloudLoadBalancersClient.class, CloudLoadBalancersAsyncClient.class, DELEGATE_MAP);
} }
@Override
protected void installLocations() { protected void installLocations() {
super.installLocations(); install(new LocationModule());
bind(RegionIdToURISupplier.class).to(RegionUrisFromPropertiesAndAccountIDPathSuffix.class).in(Scopes.SINGLETON); install(new URIWithAccountIDPathSuffixAuthenticationServiceModule());
} }
protected void bindRegionsToProvider(Class<? extends javax.inject.Provider<Map<String, URI>>> providerClass) { public static class URIWithAccountIDPathSuffixAuthenticationServiceModule extends AbstractModule {
bind(new TypeLiteral<Map<String, URI>>() {
}).annotatedWith(Region.class).toProvider(providerClass).in(Scopes.SINGLETON); @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 @Override
protected void configure() { protected void configure() {
install(module);
bind(DateAdapter.class).to(Iso8601DateAdapter.class); bind(DateAdapter.class).to(Iso8601DateAdapter.class);
install(new FactoryModuleBuilder().build(ConvertLB.Factory.class)); install(new FactoryModuleBuilder().build(ConvertLB.Factory.class));
super.configure(); 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 @Override
protected void bindErrorHandlers() { protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to( bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(
ParseCloudLoadBalancersErrorFromHttpResponse.class); ParseCloudLoadBalancersErrorFromHttpResponse.class);
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to( bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(
ParseCloudLoadBalancersErrorFromHttpResponse.class); ParseCloudLoadBalancersErrorFromHttpResponse.class);
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to( 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.HttpRequest;
import org.jclouds.http.RequiresHttp; import org.jclouds.http.RequiresHttp;
import org.jclouds.internal.ClassMethodArgs; import org.jclouds.internal.ClassMethodArgs;
import org.jclouds.location.config.LocationModule;
import org.jclouds.openstack.filters.AuthenticateRequest; 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.config.AuthenticationServiceModule.GetAuth;
import org.jclouds.openstack.keystone.v1_1.domain.Auth; import org.jclouds.openstack.keystone.v1_1.domain.Auth;
import org.jclouds.openstack.keystone.v1_1.parse.ParseAuthTest; 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.base.Throwables;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.inject.AbstractModule;
import com.google.inject.Module; import com.google.inject.Module;
import com.google.inject.Provides; import com.google.inject.Provides;
@ -77,21 +78,27 @@ public abstract class BaseCloudLoadBalancersAsyncClientTest<T> extends RestClien
@ConfiguresRestClient @ConfiguresRestClient
@RequiresHttp @RequiresHttp
protected static class TestCloudLoadBalancersRestClientModule extends CloudLoadBalancersRestClientModule { protected static class TestCloudLoadBalancersRestClientModule extends CloudLoadBalancersRestClientModule {
private TestCloudLoadBalancersRestClientModule() { @Override
super(new AuthenticationServiceModule()); 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();
} }
};
}
@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 @Override
@ -106,8 +113,8 @@ public abstract class BaseCloudLoadBalancersAsyncClientTest<T> extends RestClien
super.setupFactory(); super.setupFactory();
try { try {
processor.setCaller(new ClassMethodArgs(CloudLoadBalancersAsyncClient.class, processor.setCaller(new ClassMethodArgs(CloudLoadBalancersAsyncClient.class,
CloudLoadBalancersAsyncClient.class.getMethod("getLoadBalancerClient", String.class), CloudLoadBalancersAsyncClient.class.getMethod("getLoadBalancerClient", String.class),
new Object[] { Region.LON })); new Object[] { Region.LON }));
} catch (Exception e) { } catch (Exception e) {
Throwables.propagate(e); Throwables.propagate(e);
} }
@ -119,20 +126,20 @@ public abstract class BaseCloudLoadBalancersAsyncClientTest<T> extends RestClien
overrides.setProperty(provider + ".endpoint", "https://auth"); overrides.setProperty(provider + ".endpoint", "https://auth");
overrides.setProperty(PROPERTY_REGIONS, LON); overrides.setProperty(PROPERTY_REGIONS, LON);
overrides.setProperty(PROPERTY_REGION + "." + LON + "." + ISO3166_CODES, "GB-SLG"); overrides.setProperty(PROPERTY_REGION + "." + LON + "." + ISO3166_CODES, "GB-SLG");
overrides.setProperty(PROPERTY_REGION + "." + LON + "." + ENDPOINT, overrides.setProperty(PROPERTY_REGION + "." + LON + "." + ENDPOINT, String.format(
String.format("https://lon.loadbalancers.api.rackspacecloud.com/v${%s}", PROPERTY_API_VERSION)); "https://lon.loadbalancers.api.rackspacecloud.com/v${%s}", PROPERTY_API_VERSION));
return overrides; return overrides;
} }
/** /**
* this is only here as "cloudloadbalancers" is not in rest.properties * this is only here as "cloudloadbalancers" is not in rest.properties
*/ */
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings( { "unchecked", "rawtypes" })
@Override @Override
public RestContextSpec<?, ?> createContextSpec() { public RestContextSpec<?, ?> createContextSpec() {
return RestContextFactory.<LoadBalancerClient, LoadBalancerAsyncClient> contextSpec(provider, "https://auth", return RestContextFactory.<LoadBalancerClient, LoadBalancerAsyncClient> contextSpec(provider, "https://auth",
"1.0", "", "", "identity", "credential", LoadBalancerClient.class, LoadBalancerAsyncClient.class, "1.0", "", "", "identity", "credential", LoadBalancerClient.class, LoadBalancerAsyncClient.class,
(Class)CloudLoadBalancersPropertiesBuilder.class, (Class)CloudLoadBalancersContextBuilder.class, (Class) CloudLoadBalancersPropertiesBuilder.class, (Class) CloudLoadBalancersContextBuilder.class,
ImmutableSet.<Module> of()); ImmutableSet.<Module> of());
} }
} }

View File

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

View File

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

View File

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

View File

@ -18,12 +18,8 @@
*/ */
package org.jclouds.ec2.config; package org.jclouds.ec2.config;
import java.util.Collection;
import java.util.Map; 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.aws.config.WithZonesFormSigningRestClientModule;
import org.jclouds.ec2.EC2AsyncClient; 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.DescribeAvailabilityZonesInRegion;
import org.jclouds.ec2.suppliers.DescribeRegionsForConfiguredRegions; import org.jclouds.ec2.suppliers.DescribeRegionsForConfiguredRegions;
import org.jclouds.http.RequiresHttp; import org.jclouds.http.RequiresHttp;
import org.jclouds.location.Zone;
import org.jclouds.location.config.LocationModule; import org.jclouds.location.config.LocationModule;
import org.jclouds.location.suppliers.RegionIdToURISupplier; import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.location.suppliers.RegionIdToZoneIdsSupplier; import org.jclouds.location.suppliers.RegionIdToZoneIdsSupplier;
import org.jclouds.location.suppliers.ZoneIdsSupplier; import org.jclouds.location.suppliers.ZoneIdsSupplier;
import org.jclouds.location.suppliers.derived.ZoneIdsFromRegionIdToZoneIdsValues;
import org.jclouds.rest.ConfiguresRestClient; 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.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.inject.Scopes; 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(RegionIdToURISupplier.class).to(DescribeRegionsForConfiguredRegions.class).in(Scopes.SINGLETON);
bind(ZoneIdsSupplier.class).to(ZoneIdsFromRegionIdToZoneIdsValues.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); bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ParseNovaErrorFromHttpResponse.class);
} }
@Override
protected void bindRetryHandlers() {
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(RetryOnRenew.class);
}
@Provides @Provides
@Singleton @Singleton
@ServerManagement @ServerManagement

View File

@ -23,7 +23,6 @@ import java.net.URI;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.RequiresHttp; import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError; import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection; 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.json.config.GsonModule.Iso8601DateAdapter;
import org.jclouds.openstack.config.OpenStackAuthenticationModule; import org.jclouds.openstack.config.OpenStackAuthenticationModule;
import org.jclouds.openstack.functions.URIFromAuthenticationResponseForService; import org.jclouds.openstack.functions.URIFromAuthenticationResponseForService;
import org.jclouds.openstack.handlers.RetryOnRenew;
import org.jclouds.openstack.reference.AuthHeaders; import org.jclouds.openstack.reference.AuthHeaders;
import org.jclouds.openstack.swift.CommonSwiftAsyncClient; import org.jclouds.openstack.swift.CommonSwiftAsyncClient;
import org.jclouds.openstack.swift.CommonSwiftClient; 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); bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ParseSwiftErrorFromHttpResponse.class);
} }
@Override
protected void bindRetryHandlers() {
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(RetryOnRenew.class);
}
@Provides @Provides
@Singleton @Singleton
@Storage @Storage

View File

@ -32,13 +32,16 @@ import javax.inject.Singleton;
import org.jclouds.concurrent.RetryOnTimeOutExceptionFunction; import org.jclouds.concurrent.RetryOnTimeOutExceptionFunction;
import org.jclouds.date.TimeStamp; import org.jclouds.date.TimeStamp;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.RequiresHttp; import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.location.Provider; import org.jclouds.location.Provider;
import org.jclouds.openstack.Authentication; import org.jclouds.openstack.Authentication;
import org.jclouds.openstack.OpenStackAuthAsyncClient; import org.jclouds.openstack.OpenStackAuthAsyncClient;
import org.jclouds.openstack.OpenStackAuthClient; import org.jclouds.openstack.OpenStackAuthClient;
import org.jclouds.openstack.domain.AuthenticationResponse; import org.jclouds.openstack.domain.AuthenticationResponse;
import org.jclouds.openstack.functions.URIFromAuthenticationResponseForService; import org.jclouds.openstack.functions.URIFromAuthenticationResponseForService;
import org.jclouds.openstack.handlers.RetryOnRenew;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
@ -66,6 +69,7 @@ public class OpenStackAuthenticationModule extends AbstractModule {
// explicitly // explicitly
bindClientAndAsyncClient(binder(), OpenStackAuthClient.class, OpenStackAuthAsyncClient.class); bindClientAndAsyncClient(binder(), OpenStackAuthClient.class, OpenStackAuthAsyncClient.class);
install(new FactoryModuleBuilder().build(URIFromAuthenticationResponseForService.Factory.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.concurrent.RetryOnTimeOutExceptionFunction;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.RequiresHttp; import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.location.Provider; import org.jclouds.location.Provider;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.openstack.Authentication; import org.jclouds.openstack.Authentication;
import org.jclouds.openstack.keystone.v1_1.ServiceAsyncClient; import org.jclouds.openstack.keystone.v1_1.ServiceAsyncClient;
import org.jclouds.openstack.keystone.v1_1.ServiceClient; import org.jclouds.openstack.keystone.v1_1.ServiceClient;
import org.jclouds.openstack.keystone.v1_1.domain.Auth; 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.Function;
import com.google.common.base.Supplier; 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 // ServiceClient is used directly for filters and retry handlers, so let's bind it
// explicitly // explicitly
bindClientAndAsyncClient(binder(), ServiceClient.class, ServiceAsyncClient.class); 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 publicURL;
protected final URI internalURL; 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.v1Default = v1Default;
this.region = region; this.region = region;
this.publicURL = checkNotNull(publicURL, "publicURL"); this.publicURL = publicURL;
this.internalURL = internalURL; 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 * A public URL is accessible from anywhere. Access to a public URL usually incurs traffic
* incurs traffic charges. * charges.
* *
* @return the public endpoint of the service * @return the public endpoint of the service
*/ */
@Nullable
public URI getPublicURL() { public URI getPublicURL() {
return publicURL; 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; package org.jclouds.openstack.keystone.v1_1.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI; 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.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> { @ImplementedBy(PublicURLOrInternalIfNull.class)
private final String serviceId; public interface EndpointToSupplierURI extends Function<Endpoint, Supplier<URI>> {
public PublicUrlForService(String serviceId) {
this.serviceId = checkNotNull(serviceId, "serviceId");
}
@Override
public URI apply(Auth arg0) {
return Iterables.get(arg0.getServiceCatalog().get(serviceId), 0).getPublicURL();
}
} }

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; package org.jclouds.openstack.keystone.v1_1.functions;
import java.net.URI;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; 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.net.InternetDomainName;
import com.google.common.collect.Iterables;
import com.google.inject.assistedinject.Assisted;
@Singleton @Singleton
public class PublicURLFromAuthResponseForService implements Supplier<URI> { public class RegionFirstPartOfDNSNameOrProvider implements EndpointToRegion {
public static interface Factory { private final String provider;
PublicURLFromAuthResponseForService create(String service);
}
private final Supplier<Auth> auth;
private final String service;
@Inject @Inject
public PublicURLFromAuthResponseForService(Supplier<Auth> auth, @Assisted String service) { RegionFirstPartOfDNSNameOrProvider(@Provider String provider) {
this.auth = auth; this.provider = provider;
this.service = service;
} }
@Override @Override
public URI get() { public String apply(Endpoint input) {
return Iterables.get(auth.get().getServiceCatalog().get(service), 0).getPublicURL(); if (input.getRegion() != null)
} return input.getRegion();
String host = input.getPublicURL().getHost();
@Override if (InternetDomainName.isValid(host)) {
public String toString() { InternetDomainName domain = InternetDomainName.from(host);
return "getPublicURLForService(" + service + ")"; 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) @Consumes(MediaType.APPLICATION_JSON)
@Path("/tokens") @Path("/tokens")
@MapBinder(BindAuthToJsonPayload.class) @MapBinder(BindAuthToJsonPayload.class)
ListenableFuture<Access> authenticateTenantWithCredentials(@PayloadParam("tenantId") String tenantId, ListenableFuture<Access> authenticateTenantWithCredentials(@PayloadParam("tenantName") String tenantId,
PasswordCredentials passwordCredentials); PasswordCredentials passwordCredentials);
/** /**
@ -64,6 +64,8 @@ public interface ServiceAsyncClient {
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Path("/tokens") @Path("/tokens")
@MapBinder(BindAuthToJsonPayload.class) @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); ApiAccessKeyCredentials apiAccessKeyCredentials);
} }

View File

@ -75,8 +75,10 @@ public class BindAuthToJsonPayload extends BindToJsonPayload implements MapBinde
Builder<String, Object> builder = ImmutableMap.<String, Object> builder(); Builder<String, Object> builder = ImmutableMap.<String, Object> builder();
addCredentialsInArgsOrNull(gRequest, builder); addCredentialsInArgsOrNull(gRequest, builder);
if (Strings.emptyToNull(postParams.get("tenantId")) != null) // TODO: is tenantName permanent? or should we switch to tenantId at some point. seems most tools
builder.put("tenantId", postParams.get("tenantId")); // 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())); 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.RequiresHttp;
import org.jclouds.http.annotation.ClientError; import org.jclouds.http.annotation.ClientError;
import org.jclouds.location.Provider; 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.Authentication;
import org.jclouds.openstack.keystone.v2_0.ServiceAsyncClient; import org.jclouds.openstack.keystone.v2_0.ServiceAsyncClient;
import org.jclouds.openstack.keystone.v2_0.ServiceClient; import org.jclouds.openstack.keystone.v2_0.ServiceClient;
import org.jclouds.openstack.keystone.v2_0.domain.Access; 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.AuthenticateApiAccessKeyCredentials;
import org.jclouds.openstack.keystone.v2_0.functions.AuthenticatePasswordCredentials; 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.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.Function;
import com.google.common.base.Supplier; 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 // ServiceClient is used directly for filters and retry handlers, so let's bind it
// explicitly // explicitly
bindClientAndAsyncClient(binder(), ServiceClient.class, ServiceAsyncClient.class); 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; package org.jclouds.openstack.keystone.v2_0.config;
import org.jclouds.openstack.services.ServiceType;
/** /**
* Configuration properties and constants used in Keystone connections. * 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"; 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 org.jclouds.javax.annotation.Nullable;
import com.google.common.base.Objects; 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 * 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 { public static class Builder {
protected String id; protected String versionId;
protected String region; protected String region;
protected URI publicURL; protected URI publicURL;
protected URI internalURL;
protected String tenantId; protected String tenantId;
/** /**
* @see Endpoint#getId() * @see Endpoint#getVersionId()
*/ */
public Builder id(String id) { public Builder versionId(String versionId) {
this.id = checkNotNull(id, "id"); this.versionId = checkNotNull(versionId, "versionId");
return this; return this;
} }
@ -79,6 +81,14 @@ public class Endpoint implements Comparable<Endpoint> {
return this; return this;
} }
/**
* @see Endpoint#getInternalURL()
*/
public Builder internalURL(URI internalURL) {
this.internalURL = checkNotNull(internalURL, "internalURL");
return this;
}
/** /**
* @see Endpoint#getTenantId() * @see Endpoint#getTenantId()
*/ */
@ -88,34 +98,43 @@ public class Endpoint implements Comparable<Endpoint> {
} }
public Endpoint build() { public Endpoint build() {
return new Endpoint(id, region, publicURL, tenantId); return new Endpoint(versionId, region, publicURL, internalURL, tenantId);
} }
public Builder fromEndpoint(Endpoint from) { 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());
} }
} }
// renamed half-way through
protected final String id; @Deprecated
protected String id;
protected final String versionId;
protected final String region; protected final String region;
protected final URI publicURL; protected final URI publicURL;
protected final URI internalURL;
// renamed half-way through
@Deprecated
protected String tenantName;
protected final String tenantId; protected final String tenantId;
protected Endpoint(String id, String region, URI publicURL, @Nullable String tenantId) { protected Endpoint(String versionId, String region, @Nullable URI publicURL, @Nullable URI internalURL,
this.id = checkNotNull(id, "id"); @Nullable String tenantId) {
this.versionId = checkNotNull(versionId, "versionId");
this.region = checkNotNull(region, "region"); this.region = checkNotNull(region, "region");
this.publicURL = checkNotNull(publicURL, "publicURL"); this.publicURL = publicURL;
this.internalURL = internalURL;
this.tenantId = tenantId; 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 * 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() { public String getVersionId() {
return id; 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() { public URI getPublicURL() {
return publicURL; 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 @Nullable
public String getTenantId() { public String getTenantId() {
return tenantId; return tenantId != null ? tenantId : tenantName;
} }
@Override @Override
@ -148,8 +175,8 @@ public class Endpoint implements Comparable<Endpoint> {
} }
if (object instanceof Endpoint) { if (object instanceof Endpoint) {
final Endpoint other = Endpoint.class.cast(object); final Endpoint other = Endpoint.class.cast(object);
return equal(id, other.id) && equal(region, other.region) && equal(publicURL, other.publicURL) return equal(getVersionId(), other.getVersionId()) && equal(region, other.region) && equal(publicURL, other.publicURL)
&& equal(tenantId, other.tenantId); && equal(internalURL, other.internalURL) && equal(getTenantId(), other.getTenantId());
} else { } else {
return false; return false;
} }
@ -157,22 +184,19 @@ public class Endpoint implements Comparable<Endpoint> {
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hashCode(id, region, publicURL, tenantId); return Objects.hashCode(getVersionId(), region, publicURL, internalURL, getTenantId());
} }
@Override @Override
public String toString() { public String toString() {
return toStringHelper("").add("id", id).add("region", region).add("publicURL", publicURL).add("tenantId", return toStringHelper("").add("versionId", getVersionId()).add("region", region).add("publicURL", publicURL).add("internalURL",
tenantId).toString(); internalURL).add("tenantId", getTenantId()).toString();
} }
@Override @Override
public int compareTo(Endpoint that) { public int compareTo(Endpoint that) {
if (that == null) return ComparisonChain.start().compare(this.getTenantId(), that.getTenantId()).compare(this.getVersionId(), that.getVersionId())
return 1; .compare(this.region, that.region).result();
if (this == that)
return 0;
return this.id.compareTo(that.id);
} }
} }

View File

@ -26,6 +26,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
import com.google.common.base.Objects; 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 * 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 id;
protected final String name; protected final String name;
protected final String serviceId; protected final String serviceId;
// renamed half-way through
@Deprecated
protected String tenantName;
protected final String tenantId; protected final String tenantId;
protected Role(String id, String name, @Nullable String serviceId, @Nullable 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 @Nullable
public String getTenantId() { public String getTenantId() {
return tenantId; return tenantId != null ? tenantId : tenantName;
} }
@Override @Override
@ -148,7 +152,7 @@ public class Role implements Comparable<Role> {
if (object instanceof Role) { if (object instanceof Role) {
final Role other = Role.class.cast(object); final Role other = Role.class.cast(object);
return equal(id, other.id) && equal(name, other.name) && equal(serviceId, other.serviceId) return equal(id, other.id) && equal(name, other.name) && equal(serviceId, other.serviceId)
&& equal(tenantId, other.tenantId); && equal(getTenantId(), other.getTenantId());
} else { } else {
return false; return false;
} }
@ -156,22 +160,18 @@ public class Role implements Comparable<Role> {
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hashCode(id, name, serviceId, tenantId); return Objects.hashCode(id, name, serviceId, getTenantId());
} }
@Override @Override
public String toString() { 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(); .toString();
} }
@Override @Override
public int compareTo(Role that) { public int compareTo(Role that) {
if (that == null) return ComparisonChain.start().compare(this.id, that.id).result();
return 1;
if (this == that)
return 0;
return this.id.compareTo(that.id);
} }
} }

View File

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

View File

@ -63,23 +63,28 @@ public class ParseAccessTest extends BaseItemParserTest<Access> {
Role.builder().id("00000000004004").serviceId("100").name("domainuser").build(), Role.builder().id("00000000004004").serviceId("100").name("domainuser").build(),
Role.builder().id("00000000004016").serviceId("120").name("netadmin") Role.builder().id("00000000004016").serviceId("120").name("netadmin")
.tenantId("40806637803162").build()).build()).serviceCatalog( .tenantId("40806637803162").build()).build()).serviceCatalog(
Service.builder().name("Object Storage").type("object-store").endpoints( Service.builder().name("Object Storage").type("object-store").endpoints(
Endpoint.builder().tenantId("40806637803162").publicURL( Endpoint.builder().tenantId("40806637803162").publicURL(
URI.create("https://objects.jclouds.org/v1.0/40806637803162")) 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( Service.builder().name("Identity").type("identity").endpoints(
Endpoint.builder().publicURL(URI.create("https://csnode.jclouds.org/v2.0/")).region( Endpoint.builder().publicURL(URI.create("https://csnode.jclouds.org/v2.0/")).region(
"region-a.geo-1").id("2.0").build()).build(), "region-a.geo-1").versionId("2.0").build()).build(),
Service.builder()
.name("Image Management").type("image").endpoints( Service.builder().name("Image Management").type("image").endpoints(
Endpoint.builder().tenantId("40806637803162").publicURL( Endpoint.builder().tenantId("40806637803162").publicURL(
URI.create("https://glance.jclouds.org:9292/v1.0")).region("az-1.region-a.geo-1").id( URI.create("https://glance.jclouds.org:9292/v1.0")).region("az-1.region-a.geo-1")
"1.0").build()).build(), .versionId("1.0").build()).build(),
Service.builder().name("Compute").type("compute").endpoints(
Endpoint.builder().tenantId("40806637803162").publicURL( Service.builder().name("Cloud Servers").type("compute").endpoints(
URI.create("http://compute-1.jclouds.org:8774/v1.1/40806637803162")).region( Endpoint.builder().tenantId("1").publicURL(URI.create("https://compute.north.host/v1/1234"))
"az-1.region-a.geo-1").id("1.1").build()).build()).build(); .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", "id": "00000000004022",
"serviceId": "110", "serviceId": "110",
"name": "Admin", "name": "Admin",
"tenantId": "40806637803162" "tenantName": "40806637803162"
}, },
{ {
"id": "00000000004024", "id": "00000000004024",
"serviceId": "140", "serviceId": "140",
"name": "user", "name": "user",
"tenantId": "40806637803162" "tenantName": "40806637803162"
}, },
{ {
"id": "00000000004004", "id": "00000000004004",
@ -33,7 +33,7 @@
"id": "00000000004016", "id": "00000000004016",
"serviceId": "120", "serviceId": "120",
"name": "netadmin", "name": "netadmin",
"tenantId": "40806637803162" "tenantName": "40806637803162"
} }
] ]
}, },
@ -43,7 +43,7 @@
"type": "object-store", "type": "object-store",
"endpoints": [ "endpoints": [
{ {
"tenantId": "40806637803162", "tenantName": "40806637803162",
"adminURL": "https://objects.jclouds.org/v1.0/", "adminURL": "https://objects.jclouds.org/v1.0/",
"publicURL": "https://objects.jclouds.org/v1.0/40806637803162", "publicURL": "https://objects.jclouds.org/v1.0/40806637803162",
"region": "region-a.geo-1", "region": "region-a.geo-1",
@ -68,7 +68,7 @@
"type": "image", "type": "image",
"endpoints": [ "endpoints": [
{ {
"tenantId": "40806637803162", "tenantName": "40806637803162",
"publicURL": "https://glance.jclouds.org:9292/v1.0", "publicURL": "https://glance.jclouds.org:9292/v1.0",
"region": "az-1.region-a.geo-1", "region": "az-1.region-a.geo-1",
"id": "1.0" "id": "1.0"
@ -76,17 +76,28 @@
] ]
}, },
{ {
"name": "Compute", "name":"Cloud Servers",
"type": "compute", "type":"compute",
"endpoints": [ "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", "tenantId":"2",
"publicURL": "http://compute-1.jclouds.org:8774/v1.1/40806637803162", "publicURL":"https://compute.north.host/v1.1/3456",
"region": "az-1.region-a.geo-1", "internalURL":"https://compute.north.host/v1.1/3456",
"id": "1.1", "region":"North",
"list": "http://compute-1.jclouds.org:8774" "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.common.base.Supplier;
import com.google.inject.ImplementedBy; import com.google.inject.ImplementedBy;
import com.google.inject.assistedinject.Assisted;
/** /**
* *
@ -33,5 +34,18 @@ import com.google.inject.ImplementedBy;
*/ */
@ImplementedBy(RegionIdToURIFromConfigurationOrDefaultToProvider.class) @ImplementedBy(RegionIdToURIFromConfigurationOrDefaultToProvider.class)
public interface RegionIdToURISupplier extends Supplier<Map<String, Supplier<URI>>> { 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; package org.jclouds.rest.internal;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.concurrent.ExecutionException; 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.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.Binding;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.google.inject.Key; import com.google.inject.Key;
import com.google.inject.Provides; import com.google.inject.Provides;
import com.google.inject.ProvisionException; import com.google.inject.ProvisionException;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
import com.google.inject.util.Types;
/** /**
* Generates RESTful clients from appropriately annotated interfaces. * Generates RESTful clients from appropriately annotated interfaces.
* <p/> * <p/>
* Particularly, this code delegates calls to other things. * Particularly, this code delegates calls to other things.
* <ol> * <ol>
* <li>if the method has a {@link Provides} annotation, it responds via a * <li>if the method has a {@link Provides} annotation, it responds via a {@link Injector} lookup</li>
* {@link Injector} lookup</li> * <li>if the method has a {@link Delegate} annotation, it responds with an instance of interface
* <li>if the method has a {@link Delegate} annotation, it responds with an * set in returnVal, adding the current JAXrs annotations to whatever are on that class.</li>
* instance of interface set in returnVal, adding the current JAXrs annotations
* to whatever are on that class.</li>
* <ul> * <ul>
* <li>ex. if the method with {@link Delegate} has a {@link Path} annotation, * <li>ex. if the method with {@link Delegate} has a {@link Path} annotation, and the returnval
* and the returnval interface also has {@link Path}, these values are combined. * interface also has {@link Path}, these values are combined.</li>
* </li>
* </ul> * </ul>
* <li>if {@link RestAnnotationProcessor#delegationMap} contains a mapping for * <li>if {@link RestAnnotationProcessor#delegationMap} contains a mapping for this, and the
* this, and the returnVal is properly assigned as a {@link ListenableFuture}, * returnVal is properly assigned as a {@link ListenableFuture}, it responds with an http
* it responds with an http implementation.</li> * implementation.</li>
* <li>otherwise a RuntimeException is thrown with a message including: * <li>otherwise a RuntimeException is thrown with a message including: {@code method is intended
* {@code method is intended solely to set constants}</li> * solely to set constants}</li>
* </ol> * </ol>
* *
* @author Adrian Cole * @author Adrian Cole
@ -133,7 +133,8 @@ public class AsyncRestClientProxy<T> implements InvocationHandler {
} else if (isRestCall(method)) { } else if (isRestCall(method)) {
return createListenableFutureForHttpRequestMappedToMethodAndArgs(method, args); return createListenableFutureForHttpRequestMappedToMethodAndArgs(method, args);
} else { } 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) { public Object lookupValueFromGuice(Method method) {
try { try {
Type genericReturnType = method.getGenericReturnType();
try { try {
Annotation qualifier = Iterables.find(ImmutableList.copyOf(method.getAnnotations()), isQualifierPresent); 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) { } catch (NoSuchElementException e) {
return injector.getInstance(Key.get(method.getGenericReturnType())); return injector.getInstance(Key.get(genericReturnType));
} }
} catch (ProvisionException e) { } catch (ProvisionException e) {
AuthorizationException aex = Throwables2.getFirstThrowableOfType(e, AuthorizationException.class); AuthorizationException aex = Throwables2.getFirstThrowableOfType(e, AuthorizationException.class);
@ -163,7 +171,8 @@ public class AsyncRestClientProxy<T> implements InvocationHandler {
} }
@SuppressWarnings( { "unchecked", "rawtypes" }) @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); method = annotationProcessor.getDelegateOrNull(method);
logger.trace("Converting %s.%s", declaring.getSimpleName(), method.getName()); logger.trace("Converting %s.%s", declaring.getSimpleName(), method.getName());
Function<Exception, ?> exceptionParser = annotationProcessor 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)); String.format("endpoint for [%s] not configured for %s", args[index], method));
return returnVal; return returnVal;
} catch (NullPointerException e) { } 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 { } else {
SortedSet<Integer> keys = newTreeSet(map.keySet()); 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.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.Serializable; import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.google.common.annotations.VisibleForTesting; 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.Preconditions;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import com.google.common.collect.Iterables;
import com.google.common.io.OutputSupplier; import com.google.common.io.OutputSupplier;
/** /**
@ -38,6 +40,21 @@ import com.google.common.io.OutputSupplier;
*/ */
public class Suppliers2 { 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() { public static <X> Function<X, Supplier<X>> ofInstanceFunction() {
return new Function<X, Supplier<X>>(){ return new Function<X, Supplier<X>>(){

View File

@ -202,6 +202,11 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@Timeout(duration = 10, timeUnit = TimeUnit.NANOSECONDS) @Timeout(duration = 10, timeUnit = TimeUnit.NANOSECONDS)
public static interface Caller { public static interface Caller {
// tests that we can pull from suppliers
@Provides
@Localhost2
URI getURI();
@Delegate @Delegate
public Callee getCallee(); public Callee getCallee();
@ -216,6 +221,9 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
} }
public static interface AsyncCaller { public static interface AsyncCaller {
@Provides
@Localhost2
URI getURI();
@Delegate @Delegate
public AsyncCallee getCallee(); 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");
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(); 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 { 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.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.io.Serializable; import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger; 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.Function;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
public class Suppliers2Test { 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 @Test
public void testMemoizeKeepsValueForFullDurationWhenDelegateCallIsSlow() { public void testMemoizeKeepsValueForFullDurationWhenDelegateCallIsSlow() {
final long SLEEP_TIME = 250; final long SLEEP_TIME = 250;

View File

@ -37,7 +37,7 @@
<!-- keystone endpoint --> <!-- keystone endpoint -->
<test.openstack-nova.endpoint>http://localhost:5000</test.openstack-nova.endpoint> <test.openstack-nova.endpoint>http://localhost:5000</test.openstack-nova.endpoint>
<!-- keystone version --> <!-- 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.build-version></test.openstack-nova.build-version>
<test.openstack-nova.identity>FIXME_IDENTITY</test.openstack-nova.identity> <test.openstack-nova.identity>FIXME_IDENTITY</test.openstack-nova.identity>
<test.openstack-nova.credential>FIXME_CREDENTIALS</test.openstack-nova.credential> <test.openstack-nova.credential>FIXME_CREDENTIALS</test.openstack-nova.credential>

View File

@ -18,8 +18,16 @@
*/ */
package org.jclouds.openstack.nova.v1_1; 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.openstack.nova.v1_1.features.ServerAsyncClient;
import org.jclouds.rest.annotations.Delegate; 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. * Provides asynchronous access to Nova via their REST API.
@ -31,10 +39,19 @@ import org.jclouds.rest.annotations.Delegate;
*/ */
public interface NovaAsyncClient { public interface NovaAsyncClient {
/**
*
* @return the region codes configured
*/
@Provides
@Region
Set<String> getConfiguredRegions();
/** /**
* Provides asynchronous access to Server features. * Provides asynchronous access to Server features.
*/ */
@Delegate @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; package org.jclouds.openstack.nova.v1_1;
import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout; 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.openstack.nova.v1_1.features.ServerClient;
import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam;
import com.google.inject.Provides;
/** /**
* Provides synchronous access to Nova. * Provides synchronous access to Nova.
@ -34,11 +41,19 @@ import org.jclouds.rest.annotations.Delegate;
*/ */
@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS) @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
public interface NovaClient { public interface NovaClient {
/**
*
* @return the region codes configured
*/
@Provides
@Region
Set<String> getConfiguredRegions();
/** /**
* Provides synchronous access to Server features. * Provides synchronous access to Server features.
*/ */
@Delegate @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 java.util.Properties;
import org.jclouds.PropertiesBuilder; 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 * Builds properties used in Nova Clients
@ -34,9 +36,11 @@ public class NovaPropertiesBuilder extends PropertiesBuilder {
@Override @Override
protected Properties defaultProperties() { protected Properties defaultProperties() {
Properties properties = super.defaultProperties(); Properties properties = super.defaultProperties();
// TODO: keystone
properties.setProperty(PROPERTY_ENDPOINT, "http://localhost:5000"); 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; return properties;
} }

View File

@ -18,31 +18,23 @@
*/ */
package org.jclouds.openstack.nova.v1_1.config; package org.jclouds.openstack.nova.v1_1.config;
import java.net.URI;
import java.util.Map; import java.util.Map;
import javax.inject.Singleton;
import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.RequiresHttp; import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError; import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection; import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError; import org.jclouds.http.annotation.ServerError;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule; 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.NovaAsyncClient;
import org.jclouds.openstack.nova.v1_1.NovaClient; 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.ServerAsyncClient;
import org.jclouds.openstack.nova.v1_1.features.ServerClient; import org.jclouds.openstack.nova.v1_1.features.ServerClient;
import org.jclouds.openstack.nova.v1_1.handlers.NovaErrorHandler; 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.ConfiguresRestClient;
import org.jclouds.rest.config.RestClientModule; import org.jclouds.rest.config.RestClientModule;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.inject.Provides;
/** /**
* Configures the Nova connection. * Configures the Nova connection.
@ -57,35 +49,29 @@ public class NovaRestClientModule extends RestClientModule<NovaClient, NovaAsync
.put(ServerClient.class, ServerAsyncClient.class)// .put(ServerClient.class, ServerAsyncClient.class)//
.build(); .build();
private final KeystoneAuthenticationModule authModule;
public NovaRestClientModule() { public NovaRestClientModule() {
this(new KeystoneAuthenticationModule());
}
public NovaRestClientModule(KeystoneAuthenticationModule authModule) {
super(NovaClient.class, NovaAsyncClient.class, DELEGATE_MAP); super(NovaClient.class, NovaAsyncClient.class, DELEGATE_MAP);
this.authModule = authModule;
} }
@Override @Override
protected void configure() { protected void configure() {
install(authModule);
install(new NovaParserModule()); install(new NovaParserModule());
super.configure(); 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 @Override
protected void bindErrorHandlers() { protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(NovaErrorHandler.class); bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(NovaErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(NovaErrorHandler.class); bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(NovaErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ServerError.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.domain.Resource;
import org.jclouds.openstack.filters.AuthenticateRequest; import org.jclouds.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.nova.v1_1.domain.Server; 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.ExceptionParser;
import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.annotations.SelectJson;
@ -51,7 +49,6 @@ import com.google.common.util.concurrent.ListenableFuture;
*/ */
@SkipEncoding({ '/', '=' }) @SkipEncoding({ '/', '=' })
@RequestFilters(AuthenticateRequest.class) @RequestFilters(AuthenticateRequest.class)
@Endpoint(Compute.class)
public interface ServerAsyncClient { public interface ServerAsyncClient {
/** /**

View File

@ -25,12 +25,13 @@ import java.util.Properties;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; 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.internal.BaseNovaRestClientExpectTest;
import org.jclouds.openstack.nova.v1_1.parse.ParseServerListTest; import org.jclouds.openstack.nova.v1_1.parse.ParseServerListTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap; 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") @Test(groups = "unit", testName = "PasswordAuthenticationExpectTest")
public class PasswordAuthenticationExpectTest extends BaseNovaRestClientExpectTest { 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 * 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 { public void testListServersWhenResponseIs2xx() throws Exception {
HttpRequest listServers = HttpRequest.builder().method("GET").endpoint( 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", ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build()).build(); authToken).build()).build();
HttpResponse listServersResponse = HttpResponse.builder().statusCode(200).payload( HttpResponse listServersResponse = HttpResponse.builder().statusCode(200).payload(
payloadFromResource("/server_list.json")).build(); payloadFromResource("/server_list.json")).build();
ServerClient clientWhenServersExist = requestsSendResponses(initialAuthWithPasswordCredentials, NovaClient clientWhenServersExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
responseWithAccess, listServers, listServersResponse).getServerClient(); 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.HttpRequest;
import org.jclouds.http.HttpResponse; 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.internal.BaseNovaRestClientExpectTest;
import org.jclouds.openstack.nova.v1_1.parse.ParseServerListTest; import org.jclouds.openstack.nova.v1_1.parse.ParseServerListTest;
import org.jclouds.openstack.nova.v1_1.parse.ParseServerTest; import org.jclouds.openstack.nova.v1_1.parse.ParseServerTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
/** /**
* Tests annotation parsing of {@code ServerAsyncClient} * Tests annotation parsing of {@code ServerAsyncClient}
@ -22,53 +24,53 @@ import com.google.common.collect.ImmutableMultimap;
@Test(groups = "unit", testName = "ServerAsyncClientTest") @Test(groups = "unit", testName = "ServerAsyncClientTest")
public class ServerClientExpectTest extends BaseNovaRestClientExpectTest { public class ServerClientExpectTest extends BaseNovaRestClientExpectTest {
public ServerClientExpectTest() {
provider = "openstack-nova";
}
public void testListServersWhenResponseIs2xx() throws Exception { public void testListServersWhenResponseIs2xx() throws Exception {
HttpRequest listServers = HttpRequest.builder().method("GET").endpoint( 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", ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build()).build(); authToken).build()).build();
HttpResponse listServersResponse = HttpResponse.builder().statusCode(200).payload( HttpResponse listServersResponse = HttpResponse.builder().statusCode(200).payload(
payloadFromResource("/server_list.json")).build(); payloadFromResource("/server_list.json")).build();
ServerClient clientWhenServersExist = requestsSendResponses(initialAuthWithApiAccessKeyCredentials, NovaClient clientWhenServersExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey,
responseWithAccess, listServers, listServersResponse).getServerClient(); 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 { public void testListServersWhenReponseIs404IsEmpty() throws Exception {
HttpRequest listServers = HttpRequest.builder().method("GET").endpoint( 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", ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build()).build(); authToken).build()).build();
HttpResponse listServersResponse = HttpResponse.builder().statusCode(404).build(); HttpResponse listServersResponse = HttpResponse.builder().statusCode(404).build();
ServerClient clientWhenServersExist = requestsSendResponses(initialAuthWithApiAccessKeyCredentials, NovaClient clientWhenNoServersExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey,
responseWithAccess, listServers, listServersResponse).getServerClient(); responseWithKeystoneAccess, listServers, listServersResponse);
assertTrue(clientWhenServersExist.listServers().isEmpty()); assertTrue(clientWhenNoServersExist.getServerClientForRegion("North").listServers().isEmpty());
} }
// TODO: gson deserializer for Multimap // TODO: gson deserializer for Multimap
public void testGetServerWhenResponseIs2xx() throws Exception { public void testGetServerWhenResponseIs2xx() throws Exception {
HttpRequest listServers = HttpRequest.builder().method("GET").endpoint( 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", ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build()).build(); authToken).build()).build();
HttpResponse listServersResponse = HttpResponse.builder().statusCode(200).payload( HttpResponse listServersResponse = HttpResponse.builder().statusCode(200).payload(
payloadFromResource("/server_details.json")).build(); payloadFromResource("/server_details.json")).build();
ServerClient clientWhenServersExist = requestsSendResponses(initialAuthWithApiAccessKeyCredentials, NovaClient clientWhenServersExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey,
responseWithAccess, listServers, listServersResponse).getServerClient(); 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.domain.Resource;
import org.jclouds.openstack.nova.v1_1.domain.Server; import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientLiveTest; import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientLiveTest;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test; import org.testng.annotations.Test;
/** /**
@ -37,25 +36,20 @@ import org.testng.annotations.Test;
@Test(groups = "live", testName = "ServerClientLiveTest") @Test(groups = "live", testName = "ServerClientLiveTest")
public class ServerClientLiveTest extends BaseNovaClientLiveTest { public class ServerClientLiveTest extends BaseNovaClientLiveTest {
@BeforeGroups(groups = { "live" })
public void setupClient() {
super.setupClient();
client = context.getApi().getServerClient();
}
private ServerClient client;
@Test @Test
public void testListServersInDetail() throws Exception { public void testListServersInDetail() throws Exception {
Set<Resource> response = client.listServers(); for (String regionId : context.getApi().getConfiguredRegions()) {
assert null != response; ServerClient client = context.getApi().getServerClientForRegion(regionId);
assertTrue(response.size() >= 0); Set<Resource> response = client.listServers();
for (Resource server : response) { assert null != response;
Server newDetails = client.getServer(server.getId()); assertTrue(response.size() >= 0);
assertEquals(newDetails.getId(), server.getId()); for (Resource server : response) {
assertEquals(newDetails.getName(), server.getName()); Server newDetails = client.getServer(server.getId());
assertEquals(newDetails.getLinks(), server.getLinks()); assertEquals(newDetails.getId(), server.getId());
checkServer(newDetails); 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; package org.jclouds.openstack.nova.v1_1.internal;
import org.jclouds.http.RequiresHttp; import org.jclouds.http.HttpRequest;
import org.jclouds.openstack.keystone.v2_0.internal.BaseKeystoneRestClientExpectTest; 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.NovaClient;
import org.jclouds.openstack.nova.v1_1.config.NovaRestClientModule; import org.jclouds.rest.BaseRestClientExpectTest;
import org.jclouds.rest.ConfiguresRestClient;
import com.google.inject.Module;
/** /**
* Base class for writing KeyStone Rest Client Expect tests * Base class for writing KeyStone Rest Client Expect tests
* *
* @author Adrian Cole * @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() { public BaseNovaRestClientExpectTest() {
provider = "openstack-nova"; 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 @Singleton
public class OSTemplateToImage implements Function<OSTemplate, Image> { public class OSTemplateToImage implements Function<OSTemplate, Image> {
private final Function<String, OsFamilyVersion64Bit> imageParser; private final Function<String, OsFamilyVersion64Bit> osParser;
@Inject @Inject
public OSTemplateToImage(Function<String, OsFamilyVersion64Bit> imageParser) { public OSTemplateToImage(Function<String, OsFamilyVersion64Bit> osParser) {
this.imageParser = imageParser; this.osParser = osParser;
} }
@Override @Override
public Image apply(OSTemplate template) { public Image apply(OSTemplate template) {
checkNotNull(template, "template"); checkNotNull(template, "template");
OsFamilyVersion64Bit parsed = imageParser.apply(template.getName()); OsFamilyVersion64Bit parsed = osParser.apply(template.getName());
Builder builder = OperatingSystem.builder(); Builder builder = OperatingSystem.builder();
builder.name(template.getName()).description(template.getName()).is64Bit(parsed.is64Bit).version(parsed.version) builder.name(template.getName()).description(template.getName()).is64Bit(parsed.is64Bit).version(parsed.version)
.family(parsed.family); .family(parsed.family);