mirror of https://github.com/apache/jclouds.git
Issue 823:migrate rackspace services to authenticationservice 1.1
This commit is contained in:
parent
f93c495c43
commit
bf4b6e8c95
|
@ -25,14 +25,26 @@ import javax.inject.Singleton;
|
||||||
import org.jclouds.cloudfiles.CDNManagement;
|
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.HttpRetryHandler;
|
||||||
import org.jclouds.http.RequiresHttp;
|
import org.jclouds.http.RequiresHttp;
|
||||||
import org.jclouds.openstack.OpenStackAuthAsyncClient.AuthenticationResponse;
|
import org.jclouds.http.annotation.ClientError;
|
||||||
import org.jclouds.openstack.reference.AuthHeaders;
|
import org.jclouds.http.annotation.Redirection;
|
||||||
|
import org.jclouds.http.annotation.ServerError;
|
||||||
|
import org.jclouds.json.config.GsonModule.DateAdapter;
|
||||||
|
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
|
||||||
|
import org.jclouds.openstack.keystone.v1_1.config.AuthenticationServiceModule;
|
||||||
|
import org.jclouds.openstack.keystone.v1_1.domain.Auth;
|
||||||
|
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.config.BaseSwiftRestClientModule;
|
import org.jclouds.openstack.swift.Storage;
|
||||||
|
import org.jclouds.openstack.swift.config.SwiftObjectModule;
|
||||||
|
import org.jclouds.openstack.swift.handlers.ParseSwiftErrorFromHttpResponse;
|
||||||
import org.jclouds.rest.ConfiguresRestClient;
|
import org.jclouds.rest.ConfiguresRestClient;
|
||||||
|
import org.jclouds.rest.config.RestClientModule;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,12 +53,18 @@ import com.google.inject.Provides;
|
||||||
*/
|
*/
|
||||||
@ConfiguresRestClient
|
@ConfiguresRestClient
|
||||||
@RequiresHttp
|
@RequiresHttp
|
||||||
public class CloudFilesRestClientModule extends BaseSwiftRestClientModule<CloudFilesClient, CloudFilesAsyncClient> {
|
public class CloudFilesRestClientModule extends RestClientModule<CloudFilesClient, CloudFilesAsyncClient> {
|
||||||
|
private final AuthenticationServiceModule module;
|
||||||
|
|
||||||
public CloudFilesRestClientModule() {
|
public CloudFilesRestClientModule(AuthenticationServiceModule module) {
|
||||||
super(CloudFilesClient.class, CloudFilesAsyncClient.class);
|
super(CloudFilesClient.class, CloudFilesAsyncClient.class);
|
||||||
|
this.module = module;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CloudFilesRestClientModule() {
|
||||||
|
this(new AuthenticationServiceModule());
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
CommonSwiftClient provideCommonSwiftClient(CloudFilesClient in) {
|
CommonSwiftClient provideCommonSwiftClient(CloudFilesClient in) {
|
||||||
|
@ -62,7 +80,36 @@ public class CloudFilesRestClientModule extends BaseSwiftRestClientModule<CloudF
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
@CDNManagement
|
@CDNManagement
|
||||||
protected URI provideCDNUrl(AuthenticationResponse response) {
|
protected URI provideCDNUrl(Auth response) {
|
||||||
return response.getServices().get(AuthHeaders.CDN_MANAGEMENT_URL);
|
return Iterables.get(response.getServiceCatalog().get("cloudFilesCDN"), 0).getPublicURL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
@Storage
|
||||||
|
protected URI provideStorageUrl(Auth response) {
|
||||||
|
return Iterables.get(response.getServiceCatalog().get("cloudFiles"), 0).getPublicURL();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
install(module);
|
||||||
|
install(new SwiftObjectModule());
|
||||||
|
bind(DateAdapter.class).to(Iso8601DateAdapter.class);
|
||||||
|
super.configure();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void bindErrorHandlers() {
|
||||||
|
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ParseSwiftErrorFromHttpResponse.class);
|
||||||
|
bind(HttpErrorHandler.class).annotatedWith(ClientError.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,6 @@ public class CloudLoadBalancersPropertiesBuilder extends PropertiesBuilder {
|
||||||
protected Properties defaultProperties() {
|
protected Properties defaultProperties() {
|
||||||
Properties properties = super.defaultProperties();
|
Properties properties = super.defaultProperties();
|
||||||
properties.setProperty(PROPERTY_API_VERSION, "1.0");
|
properties.setProperty(PROPERTY_API_VERSION, "1.0");
|
||||||
|
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ import java.util.Set;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
import javax.ws.rs.core.UriBuilder;
|
||||||
|
|
||||||
import org.jclouds.cloudloadbalancers.CloudLoadBalancersAsyncClient;
|
import org.jclouds.cloudloadbalancers.CloudLoadBalancersAsyncClient;
|
||||||
import org.jclouds.cloudloadbalancers.CloudLoadBalancersClient;
|
import org.jclouds.cloudloadbalancers.CloudLoadBalancersClient;
|
||||||
|
@ -50,18 +51,17 @@ import org.jclouds.location.Provider;
|
||||||
import org.jclouds.location.Region;
|
import org.jclouds.location.Region;
|
||||||
import org.jclouds.location.config.ProvideRegionToURIViaProperties;
|
import org.jclouds.location.config.ProvideRegionToURIViaProperties;
|
||||||
import org.jclouds.logging.Logger.LoggerFactory;
|
import org.jclouds.logging.Logger.LoggerFactory;
|
||||||
import org.jclouds.openstack.OpenStackAuthAsyncClient.AuthenticationResponse;
|
import org.jclouds.openstack.keystone.v1_1.config.AuthenticationServiceModule;
|
||||||
import org.jclouds.openstack.config.OpenStackAuthenticationModule;
|
import org.jclouds.openstack.keystone.v1_1.domain.Auth;
|
||||||
import org.jclouds.openstack.handlers.RetryOnRenew;
|
import org.jclouds.openstack.keystone.v1_1.handlers.RetryOnRenew;
|
||||||
import org.jclouds.openstack.reference.AuthHeaders;
|
|
||||||
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.base.Function;
|
||||||
import com.google.common.collect.ImmutableBiMap;
|
import com.google.common.collect.ImmutableBiMap;
|
||||||
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.common.collect.Multimap;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
import com.google.inject.Scopes;
|
import com.google.inject.Scopes;
|
||||||
|
@ -83,23 +83,44 @@ public class CloudLoadBalancersRestClientModule extends
|
||||||
.put(NodeClient.class, NodeAsyncClient.class)//
|
.put(NodeClient.class, NodeAsyncClient.class)//
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
public CloudLoadBalancersRestClientModule() {
|
private final AuthenticationServiceModule module;
|
||||||
|
|
||||||
|
public CloudLoadBalancersRestClientModule(AuthenticationServiceModule module) {
|
||||||
super(CloudLoadBalancersClient.class, CloudLoadBalancersAsyncClient.class, DELEGATE_MAP);
|
super(CloudLoadBalancersClient.class, CloudLoadBalancersAsyncClient.class, DELEGATE_MAP);
|
||||||
|
this.module = module;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CloudLoadBalancersRestClientModule() {
|
||||||
|
this(new AuthenticationServiceModule());
|
||||||
|
}
|
||||||
protected void bindRegionsToProvider() {
|
protected void bindRegionsToProvider() {
|
||||||
bindRegionsToProvider(ProvideRegionToURIViaPropertiesWithAccountID.class);
|
bindRegionsToProvider(RegionUrisFromPropertiesAndAccountIDPathSuffix.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public static class ProvideRegionToURIViaPropertiesWithAccountID extends ProvideRegionToURIViaProperties {
|
public static class RegionUrisFromPropertiesAndAccountIDPathSuffix extends ProvideRegionToURIViaProperties {
|
||||||
|
|
||||||
|
private final String accountID;
|
||||||
|
private final javax.inject.Provider<UriBuilder> builders;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected ProvideRegionToURIViaPropertiesWithAccountID(Injector injector,
|
protected RegionUrisFromPropertiesAndAccountIDPathSuffix(Injector injector,
|
||||||
@Named("CONSTANTS") Multimap<String, String> constants,
|
javax.inject.Provider<UriBuilder> builders, @Named(RackspaceConstants.PROPERTY_ACCOUNT_ID) String accountID) {
|
||||||
@Named(RackspaceConstants.PROPERTY_ACCOUNT_ID) String accountID) {
|
super(injector);
|
||||||
super(injector, constants);
|
this.builders = builders;
|
||||||
constants.replaceValues(RackspaceConstants.PROPERTY_ACCOUNT_ID, ImmutableSet.of(accountID));
|
this.accountID = accountID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, URI> get() {
|
||||||
|
return Maps.transformValues(super.get(), new Function<URI, URI>(){
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URI apply(URI input) {
|
||||||
|
return builders.get().uri(input).path(accountID).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +131,7 @@ public class CloudLoadBalancersRestClientModule extends
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
install(new OpenStackAuthenticationModule());
|
install(module);
|
||||||
bind(DateAdapter.class).to(Iso8601DateAdapter.class);
|
bind(DateAdapter.class).to(Iso8601DateAdapter.class);
|
||||||
bindRegionsToProvider();
|
bindRegionsToProvider();
|
||||||
install(new FactoryModuleBuilder().build(ConvertLB.Factory.class));
|
install(new FactoryModuleBuilder().build(ConvertLB.Factory.class));
|
||||||
|
@ -120,8 +141,8 @@ public class CloudLoadBalancersRestClientModule extends
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
@Named(RackspaceConstants.PROPERTY_ACCOUNT_ID)
|
@Named(RackspaceConstants.PROPERTY_ACCOUNT_ID)
|
||||||
protected String accountID(Supplier<AuthenticationResponse> in) {
|
protected String accountID(Auth response) {
|
||||||
URI serverURL = in.get().getServices().get(AuthHeaders.SERVER_MANAGEMENT_URL);
|
URI serverURL = Iterables.get(response.getServiceCatalog().get("cloudServers"), 0).getPublicURL();
|
||||||
return serverURL.getPath().substring(serverURL.getPath().lastIndexOf('/') + 1);
|
return serverURL.getPath().substring(serverURL.getPath().lastIndexOf('/') + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,11 +42,11 @@ public class CloudLoadBalancersAsyncClientTest extends BaseCloudLoadBalancersAsy
|
||||||
private CloudLoadBalancersClient syncClient;
|
private CloudLoadBalancersClient syncClient;
|
||||||
|
|
||||||
public void testSync() throws SecurityException, NoSuchMethodException, InterruptedException, ExecutionException {
|
public void testSync() throws SecurityException, NoSuchMethodException, InterruptedException, ExecutionException {
|
||||||
assert syncClient.getLoadBalancerClient("DFW") != null;
|
assert syncClient.getLoadBalancerClient("LON") != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAsync() throws SecurityException, NoSuchMethodException, InterruptedException, ExecutionException {
|
public void testAsync() throws SecurityException, NoSuchMethodException, InterruptedException, ExecutionException {
|
||||||
assert asyncClient.getLoadBalancerClient("DFW") != null;
|
assert asyncClient.getLoadBalancerClient("LON") != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,148 +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.cloudloadbalancers.features;
|
|
||||||
|
|
||||||
import static org.testng.Assert.assertEquals;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
import org.jclouds.cloudloadbalancers.CloudLoadBalancersAsyncClient;
|
|
||||||
import org.jclouds.cloudloadbalancers.CloudLoadBalancersClient;
|
|
||||||
import org.jclouds.cloudloadbalancers.config.CloudLoadBalancersRestClientModule;
|
|
||||||
import org.jclouds.cloudloadbalancers.functions.ConvertLB;
|
|
||||||
import org.jclouds.cloudloadbalancers.reference.Region;
|
|
||||||
import org.jclouds.domain.Credentials;
|
|
||||||
import org.jclouds.http.HttpRequest;
|
|
||||||
import org.jclouds.http.RequiresHttp;
|
|
||||||
import org.jclouds.internal.ClassMethodArgs;
|
|
||||||
import org.jclouds.json.config.GsonModule.DateAdapter;
|
|
||||||
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
|
|
||||||
import org.jclouds.openstack.OpenStackAuthAsyncClient.AuthenticationResponse;
|
|
||||||
import org.jclouds.openstack.config.OpenStackAuthenticationModule;
|
|
||||||
import org.jclouds.openstack.filters.AuthenticateRequest;
|
|
||||||
import org.jclouds.rest.ConfiguresRestClient;
|
|
||||||
import org.jclouds.rest.RestClientTest;
|
|
||||||
import org.jclouds.rest.RestContext;
|
|
||||||
import org.jclouds.rest.RestContextFactory;
|
|
||||||
import org.jclouds.rest.RestContextSpec;
|
|
||||||
import org.jclouds.rest.internal.RestContextImpl;
|
|
||||||
import org.testng.annotations.BeforeClass;
|
|
||||||
|
|
||||||
import com.google.common.base.Supplier;
|
|
||||||
import com.google.common.base.Suppliers;
|
|
||||||
import com.google.common.base.Throwables;
|
|
||||||
import com.google.common.cache.LoadingCache;
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import com.google.inject.Module;
|
|
||||||
import com.google.inject.Scopes;
|
|
||||||
import com.google.inject.TypeLiteral;
|
|
||||||
import com.google.inject.assistedinject.FactoryModuleBuilder;
|
|
||||||
import com.google.inject.util.Types;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Adrian Cole
|
|
||||||
*/
|
|
||||||
public abstract class BaseCloudLoadBalancersAsyncClientTest<T> extends RestClientTest<T> {
|
|
||||||
|
|
||||||
@RequiresHttp
|
|
||||||
@ConfiguresRestClient
|
|
||||||
public static class CloudLoadBalancersRestClientModuleExtension extends CloudLoadBalancersRestClientModule {
|
|
||||||
|
|
||||||
protected void bindRegionsToProvider() {
|
|
||||||
bindRegionsToProvider(Regions.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: replace this with Expect test
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
|
||||||
protected void configure() {
|
|
||||||
// following from CloudLoadBalancersRestClientModule, except we are hard-coding the auth response
|
|
||||||
install(new OpenStackAuthenticationModule() {
|
|
||||||
@Override
|
|
||||||
protected Supplier<AuthenticationResponse> provideAuthenticationResponseSupplier(
|
|
||||||
LoadingCache<Credentials, AuthenticationResponse> cache, Credentials in) {
|
|
||||||
return Suppliers.ofInstance(new AuthenticationResponse("token", ImmutableMap.<String, URI> of()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
bind(DateAdapter.class).to(Iso8601DateAdapter.class);
|
|
||||||
bindRegionsToProvider();
|
|
||||||
install(new FactoryModuleBuilder().build(ConvertLB.Factory.class));
|
|
||||||
|
|
||||||
// following from RestClientModule
|
|
||||||
bind(new TypeLiteral<RestContext>() {
|
|
||||||
}).to(
|
|
||||||
(TypeLiteral) TypeLiteral.get(Types.newParameterizedType(
|
|
||||||
RestContextImpl.class, syncClientType, asyncClientType))).in(
|
|
||||||
Scopes.SINGLETON);
|
|
||||||
bind(TypeLiteral.get(Types.newParameterizedType(RestContext.class, syncClientType, asyncClientType))).to(
|
|
||||||
(TypeLiteral) TypeLiteral.get(Types.newParameterizedType(RestContextImpl.class, syncClientType,
|
|
||||||
asyncClientType))).in(Scopes.SINGLETON);
|
|
||||||
bindAsyncClient();
|
|
||||||
bindClient();
|
|
||||||
bindErrorHandlers();
|
|
||||||
bindRetryHandlers();
|
|
||||||
}
|
|
||||||
|
|
||||||
static class Regions implements javax.inject.Provider<Map<String, URI>> {
|
|
||||||
@Override
|
|
||||||
public Map<String, URI> get() {
|
|
||||||
return ImmutableMap.<String, URI> of("DFW", URI
|
|
||||||
.create("https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/1234"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String accountID(Supplier<AuthenticationResponse> in) {
|
|
||||||
return "1234";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void checkFilters(HttpRequest request) {
|
|
||||||
assertEquals(request.getFilters().size(), 1);
|
|
||||||
assertEquals(request.getFilters().get(0).getClass(), AuthenticateRequest.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Module createModule() {
|
|
||||||
return new CloudLoadBalancersRestClientModuleExtension();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RestContextSpec<CloudLoadBalancersClient, CloudLoadBalancersAsyncClient> createContextSpec() {
|
|
||||||
Properties props = new Properties();
|
|
||||||
return new RestContextFactory().createContextSpec("cloudloadbalancers", "email", "apikey", props);
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
@Override
|
|
||||||
protected void setupFactory() throws IOException {
|
|
||||||
super.setupFactory();
|
|
||||||
try {
|
|
||||||
processor.setCaller(new ClassMethodArgs(CloudLoadBalancersAsyncClient.class,
|
|
||||||
CloudLoadBalancersAsyncClient.class.getMethod("getLoadBalancerClient", String.class),
|
|
||||||
new Object[] { Region.DFW }));
|
|
||||||
} catch (Exception e) {
|
|
||||||
Throwables.propagate(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -54,7 +54,7 @@ public class NodeAsyncClientTest extends BaseCloudLoadBalancersAsyncClientTest<N
|
||||||
HttpRequest httpRequest = processor.createRequest(method, 2);
|
HttpRequest httpRequest = processor.createRequest(method, 2);
|
||||||
|
|
||||||
assertRequestLineEquals(httpRequest,
|
assertRequestLineEquals(httpRequest,
|
||||||
"GET https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/1234/loadbalancers/2/nodes HTTP/1.1");
|
"GET https://lon.loadbalancers.api.rackspacecloud.com/v1.0/10001786/loadbalancers/2/nodes HTTP/1.1");
|
||||||
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
|
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
|
||||||
assertPayloadEquals(httpRequest, null, null, false);
|
assertPayloadEquals(httpRequest, null, null, false);
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ public class NodeAsyncClientTest extends BaseCloudLoadBalancersAsyncClientTest<N
|
||||||
HttpRequest httpRequest = processor.createRequest(method, 3, 2);
|
HttpRequest httpRequest = processor.createRequest(method, 3, 2);
|
||||||
|
|
||||||
assertRequestLineEquals(httpRequest,
|
assertRequestLineEquals(httpRequest,
|
||||||
"GET https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/1234/loadbalancers/2/nodes/3 HTTP/1.1");
|
"GET https://lon.loadbalancers.api.rackspacecloud.com/v1.0/10001786/loadbalancers/2/nodes/3 HTTP/1.1");
|
||||||
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
|
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
|
||||||
assertPayloadEquals(httpRequest, null, null, false);
|
assertPayloadEquals(httpRequest, null, null, false);
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ public class NodeAsyncClientTest extends BaseCloudLoadBalancersAsyncClientTest<N
|
||||||
address("192.168.1.1").port(8080).build()), 3);
|
address("192.168.1.1").port(8080).build()), 3);
|
||||||
|
|
||||||
assertRequestLineEquals(httpRequest,
|
assertRequestLineEquals(httpRequest,
|
||||||
"POST https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/1234/loadbalancers/3/nodes HTTP/1.1");
|
"POST https://lon.loadbalancers.api.rackspacecloud.com/v1.0/10001786/loadbalancers/3/nodes HTTP/1.1");
|
||||||
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
|
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
|
||||||
assertPayloadEquals(
|
assertPayloadEquals(
|
||||||
httpRequest,
|
httpRequest,
|
||||||
|
@ -110,7 +110,7 @@ public class NodeAsyncClientTest extends BaseCloudLoadBalancersAsyncClientTest<N
|
||||||
HttpRequest httpRequest = processor.createRequest(method, Builder.condition(Condition.DISABLED).weight(13), 8, 7);
|
HttpRequest httpRequest = processor.createRequest(method, Builder.condition(Condition.DISABLED).weight(13), 8, 7);
|
||||||
|
|
||||||
assertRequestLineEquals(httpRequest,
|
assertRequestLineEquals(httpRequest,
|
||||||
"PUT https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/1234/loadbalancers/7/nodes/8 HTTP/1.1");
|
"PUT https://lon.loadbalancers.api.rackspacecloud.com/v1.0/10001786/loadbalancers/7/nodes/8 HTTP/1.1");
|
||||||
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
|
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
|
||||||
assertPayloadEquals(httpRequest, "{\"node\":{\"condition\":\"DISABLED\",\"weight\":13}}", "application/json", false);
|
assertPayloadEquals(httpRequest, "{\"node\":{\"condition\":\"DISABLED\",\"weight\":13}}", "application/json", false);
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ public class NodeAsyncClientTest extends BaseCloudLoadBalancersAsyncClientTest<N
|
||||||
HttpRequest httpRequest = processor.createRequest(method, 9, 4);
|
HttpRequest httpRequest = processor.createRequest(method, 9, 4);
|
||||||
|
|
||||||
assertRequestLineEquals(httpRequest,
|
assertRequestLineEquals(httpRequest,
|
||||||
"DELETE https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/1234/loadbalancers/4/nodes/9 HTTP/1.1");
|
"DELETE https://lon.loadbalancers.api.rackspacecloud.com/v1.0/10001786/loadbalancers/4/nodes/9 HTTP/1.1");
|
||||||
assertNonPayloadHeadersEqual(httpRequest, "Accept: */*\n");
|
assertNonPayloadHeadersEqual(httpRequest, "Accept: */*\n");
|
||||||
assertPayloadEquals(httpRequest, null, null, false);
|
assertPayloadEquals(httpRequest, null, null, false);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
/**
|
||||||
|
* 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.cloudloadbalancers.internal;
|
||||||
|
|
||||||
|
import static org.jclouds.Constants.PROPERTY_API_VERSION;
|
||||||
|
import static org.jclouds.cloudloadbalancers.reference.Region.LON;
|
||||||
|
import static org.jclouds.location.reference.LocationConstants.ENDPOINT;
|
||||||
|
import static org.jclouds.location.reference.LocationConstants.ISO3166_CODES;
|
||||||
|
import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGION;
|
||||||
|
import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS;
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.cloudloadbalancers.CloudLoadBalancersAsyncClient;
|
||||||
|
import org.jclouds.cloudloadbalancers.CloudLoadBalancersContextBuilder;
|
||||||
|
import org.jclouds.cloudloadbalancers.CloudLoadBalancersPropertiesBuilder;
|
||||||
|
import org.jclouds.cloudloadbalancers.config.CloudLoadBalancersRestClientModule;
|
||||||
|
import org.jclouds.cloudloadbalancers.features.LoadBalancerAsyncClient;
|
||||||
|
import org.jclouds.cloudloadbalancers.features.LoadBalancerClient;
|
||||||
|
import org.jclouds.cloudloadbalancers.reference.Region;
|
||||||
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
|
import org.jclouds.http.RequiresHttp;
|
||||||
|
import org.jclouds.internal.ClassMethodArgs;
|
||||||
|
import org.jclouds.openstack.filters.AuthenticateRequest;
|
||||||
|
import org.jclouds.openstack.keystone.v1_1.config.AuthenticationServiceModule;
|
||||||
|
import org.jclouds.openstack.keystone.v1_1.config.AuthenticationServiceModule.GetAuth;
|
||||||
|
import org.jclouds.openstack.keystone.v1_1.domain.Auth;
|
||||||
|
import org.jclouds.openstack.keystone.v1_1.parse.ParseAuthTest;
|
||||||
|
import org.jclouds.rest.ConfiguresRestClient;
|
||||||
|
import org.jclouds.rest.RestClientTest;
|
||||||
|
import org.jclouds.rest.RestContextFactory;
|
||||||
|
import org.jclouds.rest.RestContextSpec;
|
||||||
|
import org.testng.annotations.BeforeClass;
|
||||||
|
|
||||||
|
import com.google.common.base.Throwables;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.inject.Module;
|
||||||
|
import com.google.inject.Provides;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
public abstract class BaseCloudLoadBalancersAsyncClientTest<T> extends RestClientTest<T> {
|
||||||
|
|
||||||
|
protected String provider;
|
||||||
|
|
||||||
|
public BaseCloudLoadBalancersAsyncClientTest() {
|
||||||
|
this.provider = "cloudloadbalancers";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Module createModule() {
|
||||||
|
return new TestCloudLoadBalancersRestClientModule();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfiguresRestClient
|
||||||
|
@RequiresHttp
|
||||||
|
protected static class TestCloudLoadBalancersRestClientModule extends CloudLoadBalancersRestClientModule {
|
||||||
|
private TestCloudLoadBalancersRestClientModule() {
|
||||||
|
super(new AuthenticationServiceModule());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
GetAuth provideGetAuth() {
|
||||||
|
return new GetAuth(null) {
|
||||||
|
@Override
|
||||||
|
public Auth apply(Credentials in) {
|
||||||
|
return new ParseAuthTest().expected();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void checkFilters(HttpRequest request) {
|
||||||
|
assertEquals(request.getFilters().size(), 1);
|
||||||
|
assertEquals(request.getFilters().get(0).getClass(), AuthenticateRequest.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
@Override
|
||||||
|
protected void setupFactory() throws IOException {
|
||||||
|
super.setupFactory();
|
||||||
|
try {
|
||||||
|
processor.setCaller(new ClassMethodArgs(CloudLoadBalancersAsyncClient.class,
|
||||||
|
CloudLoadBalancersAsyncClient.class.getMethod("getLoadBalancerClient", String.class),
|
||||||
|
new Object[] { Region.LON }));
|
||||||
|
} catch (Exception e) {
|
||||||
|
Throwables.propagate(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Properties setupProperties() {
|
||||||
|
Properties overrides = new Properties();
|
||||||
|
overrides.setProperty(provider + ".endpoint", "https://auth");
|
||||||
|
overrides.setProperty(PROPERTY_REGIONS, LON);
|
||||||
|
overrides.setProperty(PROPERTY_REGION + "." + LON + "." + ISO3166_CODES, "GB-SLG");
|
||||||
|
overrides.setProperty(PROPERTY_REGION + "." + LON + "." + ENDPOINT,
|
||||||
|
String.format("https://lon.loadbalancers.api.rackspacecloud.com/v${%s}", PROPERTY_API_VERSION));
|
||||||
|
return overrides;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this is only here as "cloudloadbalancers" is not in rest.properties
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
|
@Override
|
||||||
|
public RestContextSpec<?, ?> createContextSpec() {
|
||||||
|
return RestContextFactory.<LoadBalancerClient, LoadBalancerAsyncClient> contextSpec(provider, "https://auth",
|
||||||
|
"1.0", "", "", "identity", "credential", LoadBalancerClient.class, LoadBalancerAsyncClient.class,
|
||||||
|
(Class)CloudLoadBalancersPropertiesBuilder.class, (Class)CloudLoadBalancersContextBuilder.class,
|
||||||
|
ImmutableSet.<Module> of());
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,7 @@
|
||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
package org.jclouds.cloudloadbalancers.features;
|
package org.jclouds.cloudloadbalancers.internal;
|
||||||
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
|
@ -47,6 +47,7 @@ import org.jclouds.cloudservers.options.RebuildServerOptions;
|
||||||
import org.jclouds.http.functions.ReturnFalseOn404;
|
import org.jclouds.http.functions.ReturnFalseOn404;
|
||||||
import org.jclouds.openstack.filters.AddTimestampQuery;
|
import org.jclouds.openstack.filters.AddTimestampQuery;
|
||||||
import org.jclouds.openstack.filters.AuthenticateRequest;
|
import org.jclouds.openstack.filters.AuthenticateRequest;
|
||||||
|
import org.jclouds.openstack.services.Compute;
|
||||||
import org.jclouds.rest.annotations.BinderParam;
|
import org.jclouds.rest.annotations.BinderParam;
|
||||||
import org.jclouds.rest.annotations.Endpoint;
|
import org.jclouds.rest.annotations.Endpoint;
|
||||||
import org.jclouds.rest.annotations.ExceptionParser;
|
import org.jclouds.rest.annotations.ExceptionParser;
|
||||||
|
@ -77,7 +78,7 @@ import com.google.common.util.concurrent.ListenableFuture;
|
||||||
*/
|
*/
|
||||||
@SkipEncoding({ '/', '=' })
|
@SkipEncoding({ '/', '=' })
|
||||||
@RequestFilters({ AuthenticateRequest.class, AddTimestampQuery.class })
|
@RequestFilters({ AuthenticateRequest.class, AddTimestampQuery.class })
|
||||||
@Endpoint(ServerManagement.class)
|
@Endpoint(Compute.class)
|
||||||
public interface CloudServersAsyncClient {
|
public interface CloudServersAsyncClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -18,14 +18,18 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.cloudservers.config;
|
package org.jclouds.cloudservers.config;
|
||||||
|
|
||||||
|
import static com.google.common.base.Suppliers.memoizeWithExpiration;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import org.jclouds.cloudservers.CloudServersAsyncClient;
|
import org.jclouds.cloudservers.CloudServersAsyncClient;
|
||||||
import org.jclouds.cloudservers.CloudServersClient;
|
import org.jclouds.cloudservers.CloudServersClient;
|
||||||
import org.jclouds.cloudservers.ServerManagement;
|
|
||||||
import org.jclouds.cloudservers.handlers.ParseCloudServersErrorFromHttpResponse;
|
import org.jclouds.cloudservers.handlers.ParseCloudServersErrorFromHttpResponse;
|
||||||
|
import org.jclouds.date.TimeStamp;
|
||||||
import org.jclouds.http.HttpErrorHandler;
|
import org.jclouds.http.HttpErrorHandler;
|
||||||
import org.jclouds.http.HttpRetryHandler;
|
import org.jclouds.http.HttpRetryHandler;
|
||||||
import org.jclouds.http.RequiresHttp;
|
import org.jclouds.http.RequiresHttp;
|
||||||
|
@ -34,13 +38,15 @@ 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.openstack.OpenStackAuthAsyncClient.AuthenticationResponse;
|
import org.jclouds.openstack.keystone.v1_1.config.AuthenticationServiceModule;
|
||||||
import org.jclouds.openstack.config.OpenStackAuthenticationModule;
|
import org.jclouds.openstack.keystone.v1_1.domain.Auth;
|
||||||
import org.jclouds.openstack.handlers.RetryOnRenew;
|
import org.jclouds.openstack.keystone.v1_1.handlers.RetryOnRenew;
|
||||||
import org.jclouds.openstack.reference.AuthHeaders;
|
import org.jclouds.openstack.services.Compute;
|
||||||
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.Iterables;
|
||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,15 +57,15 @@ import com.google.inject.Provides;
|
||||||
@RequiresHttp
|
@RequiresHttp
|
||||||
public class CloudServersRestClientModule extends RestClientModule<CloudServersClient, CloudServersAsyncClient> {
|
public class CloudServersRestClientModule extends RestClientModule<CloudServersClient, CloudServersAsyncClient> {
|
||||||
|
|
||||||
private final OpenStackAuthenticationModule module;
|
private final AuthenticationServiceModule module;
|
||||||
|
|
||||||
public CloudServersRestClientModule(OpenStackAuthenticationModule module) {
|
public CloudServersRestClientModule(AuthenticationServiceModule module) {
|
||||||
super(CloudServersClient.class, CloudServersAsyncClient.class);
|
super(CloudServersClient.class, CloudServersAsyncClient.class);
|
||||||
this.module = module;
|
this.module = module;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CloudServersRestClientModule() {
|
public CloudServersRestClientModule() {
|
||||||
this(new OpenStackAuthenticationModule());
|
this(new AuthenticationServiceModule());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -83,9 +89,20 @@ public class CloudServersRestClientModule extends RestClientModule<CloudServersC
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
@ServerManagement
|
@Compute
|
||||||
protected URI provideServerUrl(AuthenticationResponse response) {
|
protected URI provideServerUrl(Auth response) {
|
||||||
return response.getServices().get(AuthHeaders.SERVER_MANAGEMENT_URL);
|
return Iterables.get(response.getServiceCatalog().get("cloudServers"), 0).getPublicURL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: see if we still need this.
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
@TimeStamp
|
||||||
|
protected Supplier<Date> provideCacheBusterDate() {
|
||||||
|
return memoizeWithExpiration(new Supplier<Date>() {
|
||||||
|
public Date get() {
|
||||||
|
return new Date();
|
||||||
|
}
|
||||||
|
}, 1, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,8 @@ public class OpenStackAuthenticationModule extends AbstractModule {
|
||||||
public static class GetAuthenticationResponse extends
|
public static class GetAuthenticationResponse extends
|
||||||
RetryOnTimeOutExceptionFunction<Credentials, AuthenticationResponse> {
|
RetryOnTimeOutExceptionFunction<Credentials, AuthenticationResponse> {
|
||||||
|
|
||||||
|
// passing factory here to avoid a circular dependency on
|
||||||
|
// OpenStackAuthAsyncClient resolving OpenStackAuthAsyncClient
|
||||||
@Inject
|
@Inject
|
||||||
public GetAuthenticationResponse(final AsyncClientFactory factory) {
|
public GetAuthenticationResponse(final AsyncClientFactory factory) {
|
||||||
super(new Function<Credentials, AuthenticationResponse>() {
|
super(new Function<Credentials, AuthenticationResponse>() {
|
||||||
|
|
|
@ -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.openstack.keystone.v1_1;
|
||||||
|
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
import org.jclouds.openstack.keystone.v1_1.binders.BindCredentialsToJsonPayload;
|
||||||
|
import org.jclouds.openstack.keystone.v1_1.domain.Auth;
|
||||||
|
import org.jclouds.rest.annotations.MapBinder;
|
||||||
|
import org.jclouds.rest.annotations.PayloadParam;
|
||||||
|
import org.jclouds.rest.annotations.SelectJson;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides asynchronous access to Service via their REST API.
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @see ServiceClient
|
||||||
|
* @see <a href=
|
||||||
|
* "http://docs.openstack.org/api/openstack-identity-service/2.0/content/Service_API_Client_Operations.html"
|
||||||
|
* />
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Path("/v1.1")
|
||||||
|
public interface ServiceAsyncClient {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see ServiceClient#authenticate
|
||||||
|
*/
|
||||||
|
@POST
|
||||||
|
@SelectJson("auth")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@Path("/auth")
|
||||||
|
@MapBinder(BindCredentialsToJsonPayload.class)
|
||||||
|
ListenableFuture<Auth> authenticate(@PayloadParam("username") String username, @PayloadParam("key") String key);
|
||||||
|
|
||||||
|
}
|
|
@ -16,25 +16,29 @@
|
||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
package org.jclouds.cloudservers;
|
package org.jclouds.openstack.keystone.v1_1;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
import javax.inject.Qualifier;
|
import org.jclouds.concurrent.Timeout;
|
||||||
|
import org.jclouds.openstack.keystone.v1_1.domain.Auth;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a component related to Rackspace Cloud Servers.
|
* Provides synchronous access to the KeyStone Service API.
|
||||||
|
* <p/>
|
||||||
*
|
*
|
||||||
* @see <a href="http://docs.rackspacecloud.com/servers/api/cs-devguide-latest.pdf" />
|
* @see ServiceAsyncClient
|
||||||
|
* @see <a href="http://docs.openstack.org/api/openstack-identity-service/2.0/content/Service_API_Client_Operations.html"
|
||||||
|
* />
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Retention(value = RetentionPolicy.RUNTIME)
|
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
|
||||||
@Target(value = { ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
|
public interface ServiceClient {
|
||||||
@Qualifier
|
|
||||||
public @interface ServerManagement {
|
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* Authenticate to generate a token.
|
||||||
|
*
|
||||||
|
* @return access with token
|
||||||
|
*/
|
||||||
|
Auth authenticate(String username, String key);
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
/**
|
||||||
|
* 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.binders;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
|
import org.jclouds.json.Json;
|
||||||
|
import org.jclouds.rest.MapBinder;
|
||||||
|
import org.jclouds.rest.binders.BindToJsonPayload;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class BindCredentialsToJsonPayload extends BindToJsonPayload implements MapBinder {
|
||||||
|
@Inject
|
||||||
|
public BindCredentialsToJsonPayload(Json jsonBinder) {
|
||||||
|
super(jsonBinder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
|
||||||
|
throw new IllegalStateException("BindCredentialsToJsonPayload needs parameters");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <R extends HttpRequest> R bindToRequest(R request, Map<String, String> postParams) {
|
||||||
|
return super.bindToRequest(request, ImmutableMap.of("credentials", postParams));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,147 @@
|
||||||
|
/**
|
||||||
|
* 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.config;
|
||||||
|
|
||||||
|
import static com.google.common.base.Throwables.propagate;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.Constants;
|
||||||
|
import org.jclouds.concurrent.RetryOnTimeOutExceptionFunction;
|
||||||
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.http.RequiresHttp;
|
||||||
|
import org.jclouds.location.Provider;
|
||||||
|
import org.jclouds.openstack.Authentication;
|
||||||
|
import org.jclouds.openstack.keystone.v1_1.ServiceAsyncClient;
|
||||||
|
import org.jclouds.openstack.keystone.v1_1.domain.Auth;
|
||||||
|
import org.jclouds.rest.AsyncClientFactory;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
|
import com.google.common.base.Throwables;
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import com.google.common.cache.CacheLoader;
|
||||||
|
import com.google.common.cache.LoadingCache;
|
||||||
|
import com.google.inject.AbstractModule;
|
||||||
|
import com.google.inject.Provides;
|
||||||
|
import com.google.inject.TypeLiteral;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@RequiresHttp
|
||||||
|
public class AuthenticationServiceModule extends AbstractModule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bind(new TypeLiteral<Function<Credentials, Auth>>() {
|
||||||
|
}).to(GetAuth.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* borrowing concurrency code to ensure that caching takes place properly
|
||||||
|
*/
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
@Authentication
|
||||||
|
protected Supplier<String> provideAuthenticationTokenCache(final Supplier<Auth> supplier)
|
||||||
|
throws InterruptedException, ExecutionException, TimeoutException {
|
||||||
|
return new Supplier<String>() {
|
||||||
|
public String get() {
|
||||||
|
return supplier.get().getToken().getId();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
protected ServiceAsyncClient provideServiceClient(AsyncClientFactory factory) {
|
||||||
|
return factory.create(ServiceAsyncClient.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Provider
|
||||||
|
protected Credentials provideAuthenticationCredentials(@Named(Constants.PROPERTY_IDENTITY) String user,
|
||||||
|
@Named(Constants.PROPERTY_CREDENTIAL) String key) {
|
||||||
|
return new Credentials(user, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public static class GetAuth extends RetryOnTimeOutExceptionFunction<Credentials, Auth> {
|
||||||
|
|
||||||
|
// passing factory here to avoid a circular dependency on
|
||||||
|
// OpenStackAuthAsyncClient resolving OpenStackAuthAsyncClient
|
||||||
|
@Inject
|
||||||
|
public GetAuth(final AsyncClientFactory factory) {
|
||||||
|
super(new Function<Credentials, Auth>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Auth apply(Credentials input) {
|
||||||
|
try {
|
||||||
|
return factory.create(ServiceAsyncClient.class).authenticate(input.identity, input.credential).get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw Throwables.propagate(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "authenticate()";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
public LoadingCache<Credentials, Auth> provideAuthCache2(Function<Credentials, Auth> getAuth) {
|
||||||
|
return CacheBuilder.newBuilder().expireAfterWrite(23, TimeUnit.HOURS).build(CacheLoader.from(getAuth));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
protected Supplier<Auth> provideAuthSupplier(final LoadingCache<Credentials, Auth> cache,
|
||||||
|
@Provider final Credentials creds) {
|
||||||
|
return new Supplier<Auth>() {
|
||||||
|
@Override
|
||||||
|
public Auth get() {
|
||||||
|
try {
|
||||||
|
return cache.get(creds);
|
||||||
|
} catch (ExecutionException e) {
|
||||||
|
throw propagate(e.getCause());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
protected Auth provideAuth(Supplier<Auth> supplier) {
|
||||||
|
return supplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,137 @@
|
||||||
|
/**
|
||||||
|
* 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, User 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.domain;
|
||||||
|
|
||||||
|
import static com.google.common.base.Objects.equal;
|
||||||
|
import static com.google.common.base.Objects.toStringHelper;
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jclouds.util.Multimaps2;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
* @see <a href=
|
||||||
|
* "http://docs.rackspace.com/loadbalancers/api/v1.0/clb-devguide/content/Endpoint_Access_Endpoints-d1e517.html"
|
||||||
|
* />
|
||||||
|
*/
|
||||||
|
public class Auth implements Comparable<Auth> {
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder toBuilder() {
|
||||||
|
return builder().fromAccess(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
protected Token token;
|
||||||
|
protected Multimap<String, Endpoint> serviceCatalog = ImmutableMultimap.of();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Auth#getToken()
|
||||||
|
*/
|
||||||
|
public Builder token(Token token) {
|
||||||
|
this.token = checkNotNull(token, "token");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Auth#getServiceCatalog()
|
||||||
|
*/
|
||||||
|
public Builder serviceCatalog(Multimap<String, Endpoint> serviceCatalog) {
|
||||||
|
this.serviceCatalog = ImmutableMultimap.copyOf(checkNotNull(serviceCatalog, "serviceCatalog"));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Auth build() {
|
||||||
|
return new Auth(token, serviceCatalog);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder fromAccess(Auth from) {
|
||||||
|
return token(from.getToken()).serviceCatalog(from.getServiceCatalog());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final Token token;
|
||||||
|
// TODO: get gson multimap adapter!
|
||||||
|
protected final Map<String, Set<Endpoint>> serviceCatalog;
|
||||||
|
|
||||||
|
public Auth(Token token, Multimap<String, Endpoint> serviceCatalog) {
|
||||||
|
this.token = checkNotNull(token, "token");
|
||||||
|
this.serviceCatalog = Multimaps2.toOldSchool(ImmutableMultimap.copyOf(checkNotNull(serviceCatalog,
|
||||||
|
"serviceCatalog")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*/
|
||||||
|
public Token getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*/
|
||||||
|
public Multimap<String, Endpoint> getServiceCatalog() {
|
||||||
|
return Multimaps2.fromOldSchool(serviceCatalog);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (this == object) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (object instanceof Auth) {
|
||||||
|
final Auth other = Auth.class.cast(object);
|
||||||
|
return equal(token, other.token) && equal(serviceCatalog, other.serviceCatalog);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(token, serviceCatalog);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return toStringHelper("").add("token", token).add("serviceCatalog", serviceCatalog).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Auth that) {
|
||||||
|
if (that == null)
|
||||||
|
return 1;
|
||||||
|
if (this == that)
|
||||||
|
return 0;
|
||||||
|
return this.token.compareTo(that.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,198 @@
|
||||||
|
/**
|
||||||
|
* 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, Name 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.domain;
|
||||||
|
|
||||||
|
import static com.google.common.base.Objects.equal;
|
||||||
|
import static com.google.common.base.Objects.toStringHelper;
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import org.jclouds.javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An network-accessible address, usually described by URL, where a service may
|
||||||
|
* be accessed. If using an extension for templates, you can create an endpoint
|
||||||
|
* template, which represents the templates of all the consumable services that
|
||||||
|
* are available across the regions.
|
||||||
|
*
|
||||||
|
* @author AdrianCole
|
||||||
|
* @see <a href=
|
||||||
|
* "http://docs.rackspace.com/loadbalancers/api/v1.0/clb-devguv1Defaulte/content/Authentication-d1e699.html#Authenticate-d1e171"
|
||||||
|
* />
|
||||||
|
*/
|
||||||
|
public class Endpoint implements Comparable<Endpoint> {
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder toBuilder() {
|
||||||
|
return builder().fromEndpoint(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
|
||||||
|
protected boolean v1Default;
|
||||||
|
protected String region;
|
||||||
|
protected URI publicURL;
|
||||||
|
protected URI internalURL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Endpoint#isV1Default()
|
||||||
|
*/
|
||||||
|
public Builder v1Default(boolean v1Default) {
|
||||||
|
this.v1Default = v1Default;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Endpoint#getRegion()
|
||||||
|
*/
|
||||||
|
public Builder region(String region) {
|
||||||
|
this.region = checkNotNull(region, "region");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Endpoint#getPublicURL()
|
||||||
|
*/
|
||||||
|
public Builder publicURL(URI publicURL) {
|
||||||
|
this.publicURL = checkNotNull(publicURL, "publicURL");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Endpoint#getTenantId()
|
||||||
|
*/
|
||||||
|
public Builder internalURL(@Nullable URI internalURL) {
|
||||||
|
this.internalURL = internalURL;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Endpoint build() {
|
||||||
|
return new Endpoint(v1Default, region, publicURL, internalURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder fromEndpoint(Endpoint from) {
|
||||||
|
return v1Default(from.isV1Default()).region(from.getRegion()).publicURL(from.getPublicURL())
|
||||||
|
.internalURL(from.getInternalURL());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final boolean v1Default;
|
||||||
|
protected final String region;
|
||||||
|
protected final URI publicURL;
|
||||||
|
protected final URI internalURL;
|
||||||
|
|
||||||
|
protected Endpoint(boolean v1Default, @Nullable String region, URI publicURL, @Nullable URI internalURL) {
|
||||||
|
this.v1Default = v1Default;
|
||||||
|
this.region = region;
|
||||||
|
this.publicURL = checkNotNull(publicURL, "publicURL");
|
||||||
|
this.internalURL = internalURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The v1Default attribute denotes that an endpoint is being returned in
|
||||||
|
* version 1.0 of the Cloud Authentication Service. The default value of
|
||||||
|
* v1Default is false; clients should assume the value is false when the
|
||||||
|
* attribute is missing. Auth 1.0 does not offer support for regional
|
||||||
|
* endpoints and therefore only returns one endpoint per service. Resources
|
||||||
|
* stored in endpoints where v1Default is false will not be seen by Auth 1.0
|
||||||
|
* clients.
|
||||||
|
*
|
||||||
|
* @return whether this endpoint is visible to v1.0 clients
|
||||||
|
*/
|
||||||
|
public boolean isV1Default() {
|
||||||
|
return v1Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A service may expose endpoints in different regions. Regional endpoints
|
||||||
|
* allow clients to provision resources in a manner that provides high
|
||||||
|
* availability. <br/>
|
||||||
|
* <h3>Note</h3> Some services are not region-specific. These services supply
|
||||||
|
* a single non-regional endpoint and do not provide access to internal URLs.
|
||||||
|
*
|
||||||
|
* @return the region of the endpoint
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public String getRegion() {
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A public URL is accessible from anywhere. Access to a public URL usually
|
||||||
|
* incurs traffic charges.
|
||||||
|
*
|
||||||
|
* @return the public endpoint of the service
|
||||||
|
*/
|
||||||
|
public URI getPublicURL() {
|
||||||
|
return publicURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal URLs are only accessible to services within the same region.
|
||||||
|
* Access to an internal URL is free of charge.
|
||||||
|
*
|
||||||
|
* @return the internal url of the endpoint
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public URI getInternalURL() {
|
||||||
|
return internalURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (this == object) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (object instanceof Endpoint) {
|
||||||
|
final Endpoint other = Endpoint.class.cast(object);
|
||||||
|
return equal(v1Default, other.v1Default) && equal(region, other.region) && equal(publicURL, other.publicURL)
|
||||||
|
&& equal(internalURL, other.internalURL);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(v1Default, region, publicURL, internalURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return toStringHelper("").add("v1Default", v1Default).add("region", region).add("publicURL", publicURL)
|
||||||
|
.add("internalURL", internalURL).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Endpoint that) {
|
||||||
|
if (that == null)
|
||||||
|
return 1;
|
||||||
|
if (this == that)
|
||||||
|
return 0;
|
||||||
|
return this.publicURL.compareTo(that.publicURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
/**
|
||||||
|
* 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, Expires 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.domain;
|
||||||
|
|
||||||
|
import static com.google.common.base.Objects.equal;
|
||||||
|
import static com.google.common.base.Objects.toStringHelper;
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Tokens are valid for a finite duration. The expires attribute denotes the
|
||||||
|
* time after which the token will automatically become invalid. A token may be
|
||||||
|
* manually revoked before the time identified by the expires attribute; expires
|
||||||
|
* predicts a token's maximum possible lifespan but does not guarantee that it
|
||||||
|
* will reach that lifespan. Clients are encouraged to cache a token until it
|
||||||
|
* expires.
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
* @see <a href=
|
||||||
|
* "http://docs.rackspace.com/loadbalancers/api/v1.0/clb-devguide/content/Service_Access_Endpoints-d1e517.html"
|
||||||
|
* />
|
||||||
|
*/
|
||||||
|
public class Token implements Comparable<Token> {
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder toBuilder() {
|
||||||
|
return builder().fromToken(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
protected String id;
|
||||||
|
protected Date expires;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Token#getId()
|
||||||
|
*/
|
||||||
|
public Builder id(String id) {
|
||||||
|
this.id = checkNotNull(id, "id");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Token#getExpires()
|
||||||
|
*/
|
||||||
|
public Builder expires(Date expires) {
|
||||||
|
this.expires = checkNotNull(expires, "expires");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Token build() {
|
||||||
|
return new Token(id, expires);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder fromToken(Token from) {
|
||||||
|
return id(from.getId()).expires(from.getExpires());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final String id;
|
||||||
|
protected final Date expires;
|
||||||
|
|
||||||
|
public Token(String id, Date expires) {
|
||||||
|
this.id = checkNotNull(id, "id");
|
||||||
|
this.expires = checkNotNull(expires, "expires");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When providing an ID, it is assumed that the token exists in the current
|
||||||
|
* OpenStack deployment
|
||||||
|
*
|
||||||
|
* @return the id of the token in the current OpenStack deployment
|
||||||
|
*/
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expires of the token
|
||||||
|
*/
|
||||||
|
public Date getExpires() {
|
||||||
|
return expires;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (this == object) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (object instanceof Token) {
|
||||||
|
final Token other = Token.class.cast(object);
|
||||||
|
return equal(id, other.id) && equal(expires, other.expires);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(id, expires);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return toStringHelper("").add("id", id).add("expires", expires).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Token that) {
|
||||||
|
if (that == null)
|
||||||
|
return 1;
|
||||||
|
if (this == that)
|
||||||
|
return 0;
|
||||||
|
return this.id.compareTo(that.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
/**
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.jclouds.openstack.keystone.v1_1.handlers;
|
||||||
|
|
||||||
|
import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
|
||||||
|
import static org.jclouds.http.HttpUtils.releasePayload;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.http.HttpCommand;
|
||||||
|
import org.jclouds.http.HttpResponse;
|
||||||
|
import org.jclouds.http.HttpRetryHandler;
|
||||||
|
import org.jclouds.logging.Logger;
|
||||||
|
import org.jclouds.openstack.keystone.v1_1.domain.Auth;
|
||||||
|
import org.jclouds.openstack.reference.AuthHeaders;
|
||||||
|
|
||||||
|
import com.google.common.cache.LoadingCache;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will parse and set an appropriate exception on the command object.
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class RetryOnRenew implements HttpRetryHandler {
|
||||||
|
@Resource
|
||||||
|
protected Logger logger = Logger.NULL;
|
||||||
|
|
||||||
|
private final LoadingCache<Credentials, Auth> authenticationResponseCache;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected RetryOnRenew(LoadingCache<Credentials, Auth> authenticationResponseCache) {
|
||||||
|
this.authenticationResponseCache = authenticationResponseCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
|
||||||
|
boolean retry = false; // default
|
||||||
|
try {
|
||||||
|
switch (response.getStatusCode()) {
|
||||||
|
case 401:
|
||||||
|
// Do not retry on 401 from authentication request
|
||||||
|
Multimap<String, String> headers = command.getCurrentRequest().getHeaders();
|
||||||
|
if (headers != null && headers.containsKey(AuthHeaders.AUTH_USER)
|
||||||
|
&& headers.containsKey(AuthHeaders.AUTH_KEY) && !headers.containsKey(AuthHeaders.AUTH_TOKEN)) {
|
||||||
|
retry = false;
|
||||||
|
} else {
|
||||||
|
byte[] content = closeClientButKeepContentStream(response);
|
||||||
|
if (content != null && new String(content).contains("lease renew")) {
|
||||||
|
logger.debug("invalidating authentication token");
|
||||||
|
authenticationResponseCache.invalidateAll();
|
||||||
|
retry = true;
|
||||||
|
} else {
|
||||||
|
retry = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return retry;
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
releasePayload(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -23,7 +23,6 @@ import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
import org.jclouds.Constants;
|
|
||||||
import org.jclouds.openstack.keystone.v2_0.binders.BindAuthToJsonPayload;
|
import org.jclouds.openstack.keystone.v2_0.binders.BindAuthToJsonPayload;
|
||||||
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.domain.ApiAccessKeyCredentials;
|
import org.jclouds.openstack.keystone.v2_0.domain.ApiAccessKeyCredentials;
|
||||||
|
@ -43,7 +42,7 @@ import com.google.common.util.concurrent.ListenableFuture;
|
||||||
* />
|
* />
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
@Path("/v{" + Constants.PROPERTY_API_VERSION + "}")
|
@Path("/v2.0")
|
||||||
public interface ServiceAsyncClient {
|
public interface ServiceAsyncClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.jclouds.rest.MapBinder;
|
||||||
import org.jclouds.rest.binders.BindToJsonPayload;
|
import org.jclouds.rest.binders.BindToJsonPayload;
|
||||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableMap.Builder;
|
import com.google.common.collect.ImmutableMap.Builder;
|
||||||
|
|
||||||
|
@ -73,7 +74,8 @@ public class BindAuthToJsonPayload extends BindToJsonPayload implements MapBinde
|
||||||
checkState(gRequest.getArgs() != null, "args should be initialized at this point");
|
checkState(gRequest.getArgs() != null, "args should be initialized at this point");
|
||||||
|
|
||||||
Builder<String, Object> builder = ImmutableMap.<String, Object> builder();
|
Builder<String, Object> builder = ImmutableMap.<String, Object> builder();
|
||||||
builder.put("tenantId", postParams.get("tenantId"));
|
if (Strings.emptyToNull(postParams.get("tenantId")) != null)
|
||||||
|
builder.put("tenantId", postParams.get("tenantId"));
|
||||||
addCredentialsInArgsOrNull(gRequest, builder);
|
addCredentialsInArgsOrNull(gRequest, builder);
|
||||||
return super.bindToRequest(request, builder.build());
|
return super.bindToRequest(request, builder.build());
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,8 +95,10 @@ public class KeyStoneAuthenticationModule extends AbstractModule {
|
||||||
@Singleton
|
@Singleton
|
||||||
public static class GetAccess extends RetryOnTimeOutExceptionFunction<Credentials, Access> {
|
public static class GetAccess extends RetryOnTimeOutExceptionFunction<Credentials, Access> {
|
||||||
|
|
||||||
|
// passing factory here to avoid a circular dependency on
|
||||||
|
// OpenStackAuthAsyncClient resolving ServiceAsyncClient
|
||||||
@Inject
|
@Inject
|
||||||
public GetAccess(final ServiceAsyncClient client) {
|
public GetAccess(final AsyncClientFactory factory) {
|
||||||
super(new Function<Credentials, Access>() {
|
super(new Function<Credentials, Access>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -108,7 +110,8 @@ public class KeyStoneAuthenticationModule extends AbstractModule {
|
||||||
PasswordCredentials passwordCredentials = PasswordCredentials.createWithUsernameAndPassword(username,
|
PasswordCredentials passwordCredentials = PasswordCredentials.createWithUsernameAndPassword(username,
|
||||||
input.credential);
|
input.credential);
|
||||||
try {
|
try {
|
||||||
return client.authenticateTenantWithCredentials(tenantId, passwordCredentials).get();
|
return factory.create(ServiceAsyncClient.class)
|
||||||
|
.authenticateTenantWithCredentials(tenantId, passwordCredentials).get();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw Throwables.propagate(e);
|
throw Throwables.propagate(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
/**
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.jclouds.openstack.keystone.v2_0.handlers;
|
||||||
|
|
||||||
|
import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
|
||||||
|
import static org.jclouds.http.HttpUtils.releasePayload;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.http.HttpCommand;
|
||||||
|
import org.jclouds.http.HttpResponse;
|
||||||
|
import org.jclouds.http.HttpRetryHandler;
|
||||||
|
import org.jclouds.logging.Logger;
|
||||||
|
import org.jclouds.openstack.keystone.v2_0.domain.Access;
|
||||||
|
import org.jclouds.openstack.reference.AuthHeaders;
|
||||||
|
|
||||||
|
import com.google.common.cache.LoadingCache;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will parse and set an appropriate exception on the command object.
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class RetryOnRenew implements HttpRetryHandler {
|
||||||
|
@Resource
|
||||||
|
protected Logger logger = Logger.NULL;
|
||||||
|
|
||||||
|
private final LoadingCache<Credentials, Access> authenticationResponseCache;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected RetryOnRenew(LoadingCache<Credentials, Access> authenticationResponseCache) {
|
||||||
|
this.authenticationResponseCache = authenticationResponseCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
|
||||||
|
boolean retry = false; // default
|
||||||
|
try {
|
||||||
|
switch (response.getStatusCode()) {
|
||||||
|
case 401:
|
||||||
|
// Do not retry on 401 from authentication request
|
||||||
|
Multimap<String, String> headers = command.getCurrentRequest().getHeaders();
|
||||||
|
if (headers != null && headers.containsKey(AuthHeaders.AUTH_USER)
|
||||||
|
&& headers.containsKey(AuthHeaders.AUTH_KEY) && !headers.containsKey(AuthHeaders.AUTH_TOKEN)) {
|
||||||
|
retry = false;
|
||||||
|
} else {
|
||||||
|
byte[] content = closeClientButKeepContentStream(response);
|
||||||
|
if (content != null && new String(content).contains("lease renew")) {
|
||||||
|
logger.debug("invalidating authentication token");
|
||||||
|
authenticationResponseCache.invalidateAll();
|
||||||
|
retry = true;
|
||||||
|
} else {
|
||||||
|
retry = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return retry;
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
releasePayload(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
/**
|
||||||
|
* 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.handlers;
|
||||||
|
|
||||||
|
import static org.easymock.EasyMock.createMock;
|
||||||
|
import static org.easymock.EasyMock.expect;
|
||||||
|
import static org.easymock.EasyMock.expectLastCall;
|
||||||
|
import static org.easymock.EasyMock.replay;
|
||||||
|
import static org.easymock.EasyMock.verify;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.http.HttpCommand;
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
|
import org.jclouds.http.HttpResponse;
|
||||||
|
import org.jclouds.io.Payloads;
|
||||||
|
import org.jclouds.openstack.keystone.v1_1.domain.Auth;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.cache.LoadingCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests behavior of {@code RetryOnRenew} handler
|
||||||
|
*
|
||||||
|
* @author grkvlt@apache.org
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", testName = "RetryOnRenewTest")
|
||||||
|
public class RetryOnRenewTest {
|
||||||
|
@Test
|
||||||
|
public void test401ShouldRetry() {
|
||||||
|
HttpCommand command = createMock(HttpCommand.class);
|
||||||
|
HttpRequest request = createMock(HttpRequest.class);
|
||||||
|
HttpResponse response = createMock(HttpResponse.class);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
LoadingCache<Credentials, Auth> cache = createMock(LoadingCache.class);
|
||||||
|
|
||||||
|
expect(command.getCurrentRequest()).andReturn(request);
|
||||||
|
|
||||||
|
cache.invalidateAll();
|
||||||
|
expectLastCall();
|
||||||
|
|
||||||
|
expect(response.getPayload()).andReturn(Payloads.newStringPayload("token expired, please renew")).anyTimes();
|
||||||
|
expect(response.getStatusCode()).andReturn(401).atLeastOnce();
|
||||||
|
|
||||||
|
replay(command);
|
||||||
|
replay(response);
|
||||||
|
replay(cache);
|
||||||
|
|
||||||
|
RetryOnRenew retry = new RetryOnRenew(cache);
|
||||||
|
|
||||||
|
assertTrue(retry.shouldRetryRequest(command, response));
|
||||||
|
|
||||||
|
verify(command);
|
||||||
|
verify(response);
|
||||||
|
verify(cache);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
/**
|
||||||
|
* 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 1.1 (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-1.1
|
||||||
|
*
|
||||||
|
* 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.internal;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
|
import org.jclouds.http.HttpResponse;
|
||||||
|
import org.jclouds.openstack.keystone.v1_1.config.AuthenticationServiceModule;
|
||||||
|
import org.jclouds.rest.BaseRestClientExpectTest;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
|
import com.google.common.net.HttpHeaders;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for writing KeyStone Rest Client Expect tests
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
public class BaseKeyStoneRestClientExpectTest<S> extends BaseRestClientExpectTest<S> {
|
||||||
|
|
||||||
|
protected String endpoint = "http://localhost:5000";
|
||||||
|
|
||||||
|
public BaseKeyStoneRestClientExpectTest() {
|
||||||
|
identity = "user@jclouds.org";
|
||||||
|
credential = "Password1234";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HttpRequest initialAuth = HttpRequest
|
||||||
|
.builder()
|
||||||
|
.method("POST")
|
||||||
|
.endpoint(URI.create(endpoint + "/v1.1/auth"))
|
||||||
|
.headers(ImmutableMultimap.of(HttpHeaders.ACCEPT, "application/json"))
|
||||||
|
.payload(
|
||||||
|
payloadFromStringWithContentType(
|
||||||
|
"{\"credentials\":{\"username\":\"user@jclouds.org\",\"key\":\"Password1234\"}}",
|
||||||
|
"application/json")).build();
|
||||||
|
|
||||||
|
protected String authToken = "118fb907-0786-4799-88f0-9a5b7963d1ab";
|
||||||
|
|
||||||
|
protected HttpResponse responseWithAuth = HttpResponse.builder().statusCode(200).message("HTTP/1.1 200")
|
||||||
|
.payload(payloadFromResourceWithContentType("/auth1_1.json", "application/json")).build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* in case you need to override anything
|
||||||
|
*/
|
||||||
|
public static class TestKeyStoneAuthenticationModule extends AuthenticationServiceModule {
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
super.configure();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
/**
|
||||||
|
* 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.parse;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
import org.jclouds.date.internal.SimpleDateFormatDateService;
|
||||||
|
import org.jclouds.json.BaseItemParserTest;
|
||||||
|
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.domain.Token;
|
||||||
|
import org.jclouds.rest.annotations.SelectJson;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", testName = "ParseAuthTest")
|
||||||
|
public class ParseAuthTest extends BaseItemParserTest<Auth> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String resource() {
|
||||||
|
return "/auth1_1.json";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SelectJson("auth")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
public Auth expected() {
|
||||||
|
return Auth
|
||||||
|
.builder()
|
||||||
|
.token(
|
||||||
|
Token.builder()
|
||||||
|
.expires(new SimpleDateFormatDateService().iso8601DateParse("2012-01-30T02:30:54.000-06:00"))
|
||||||
|
.id("118fb907-0786-4799-88f0-9a5b7963d1ab").build())
|
||||||
|
.serviceCatalog(
|
||||||
|
ImmutableMultimap.of(
|
||||||
|
"cloudFilesCDN",
|
||||||
|
Endpoint
|
||||||
|
.builder()
|
||||||
|
.region("LON")
|
||||||
|
.publicURL(
|
||||||
|
URI.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"))
|
||||||
|
.v1Default(true).build(),
|
||||||
|
"cloudFiles",
|
||||||
|
Endpoint
|
||||||
|
.builder()
|
||||||
|
.region("LON")
|
||||||
|
.publicURL(
|
||||||
|
URI.create("https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"))
|
||||||
|
.v1Default(true)
|
||||||
|
.internalURL(
|
||||||
|
URI.create("https://snet-storage101.lon3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"))
|
||||||
|
.build(),
|
||||||
|
"cloudServers",
|
||||||
|
Endpoint.builder()
|
||||||
|
.publicURL(URI.create("https://lon.servers.api.rackspacecloud.com/v1.0/10001786"))
|
||||||
|
.v1Default(true).build())).build();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
/**
|
||||||
|
* 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.handlers;
|
||||||
|
|
||||||
|
import static org.easymock.EasyMock.createMock;
|
||||||
|
import static org.easymock.EasyMock.expect;
|
||||||
|
import static org.easymock.EasyMock.expectLastCall;
|
||||||
|
import static org.easymock.EasyMock.replay;
|
||||||
|
import static org.easymock.EasyMock.verify;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.http.HttpCommand;
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
|
import org.jclouds.http.HttpResponse;
|
||||||
|
import org.jclouds.io.Payloads;
|
||||||
|
import org.jclouds.openstack.keystone.v2_0.domain.Access;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.cache.LoadingCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests behavior of {@code RetryOnRenew} handler
|
||||||
|
*
|
||||||
|
* @author grkvlt@apache.org
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", testName = "RetryOnRenewTest")
|
||||||
|
public class RetryOnRenewTest {
|
||||||
|
@Test
|
||||||
|
public void test401ShouldRetry() {
|
||||||
|
HttpCommand command = createMock(HttpCommand.class);
|
||||||
|
HttpRequest request = createMock(HttpRequest.class);
|
||||||
|
HttpResponse response = createMock(HttpResponse.class);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
LoadingCache<Credentials, Access> cache = createMock(LoadingCache.class);
|
||||||
|
|
||||||
|
expect(command.getCurrentRequest()).andReturn(request);
|
||||||
|
|
||||||
|
cache.invalidateAll();
|
||||||
|
expectLastCall();
|
||||||
|
|
||||||
|
expect(response.getPayload()).andReturn(Payloads.newStringPayload("token expired, please renew")).anyTimes();
|
||||||
|
expect(response.getStatusCode()).andReturn(401).atLeastOnce();
|
||||||
|
|
||||||
|
replay(command);
|
||||||
|
replay(response);
|
||||||
|
replay(cache);
|
||||||
|
|
||||||
|
RetryOnRenew retry = new RetryOnRenew(cache);
|
||||||
|
|
||||||
|
assertTrue(retry.shouldRetryRequest(command, response));
|
||||||
|
|
||||||
|
verify(command);
|
||||||
|
verify(response);
|
||||||
|
verify(cache);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"auth": {
|
||||||
|
"token": {
|
||||||
|
"id": "118fb907-0786-4799-88f0-9a5b7963d1ab",
|
||||||
|
"expires": "2012-01-30T02:30:54.000-06:00"
|
||||||
|
},
|
||||||
|
"serviceCatalog": {
|
||||||
|
"cloudFilesCDN": [{
|
||||||
|
"region": "LON",
|
||||||
|
"publicURL": "https:\/\/cdn3.clouddrive.com\/v1\/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953",
|
||||||
|
"v1Default": true
|
||||||
|
}],
|
||||||
|
"cloudFiles": [{
|
||||||
|
"region": "LON",
|
||||||
|
"publicURL": "https:\/\/storage101.lon3.clouddrive.com\/v1\/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953",
|
||||||
|
"v1Default": true,
|
||||||
|
"internalURL": "https:\/\/snet-storage101.lon3.clouddrive.com\/v1\/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"
|
||||||
|
}],
|
||||||
|
"cloudServers": [{
|
||||||
|
"publicURL": "https:\/\/lon.servers.api.rackspacecloud.com\/v1.0\/10001786",
|
||||||
|
"v1Default": true
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,7 @@
|
||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
package org.jclouds.openstack.nova.v1_1.util;
|
package org.jclouds.util;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -31,7 +31,7 @@ import com.google.common.collect.ImmutableMultimap.Builder;
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
public class NovaUtils {
|
public class Multimaps2 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The traditional way to represent a graph in Java is Map<V, Set<V>>, which is awkward in a
|
* The traditional way to represent a graph in Java is Map<V, Set<V>>, which is awkward in a
|
|
@ -27,7 +27,7 @@ import java.util.Set;
|
||||||
import org.jclouds.openstack.domain.Link;
|
import org.jclouds.openstack.domain.Link;
|
||||||
import org.jclouds.openstack.domain.Resource;
|
import org.jclouds.openstack.domain.Resource;
|
||||||
import org.jclouds.openstack.nova.v1_1.domain.Address.Type;
|
import org.jclouds.openstack.nova.v1_1.domain.Address.Type;
|
||||||
import org.jclouds.openstack.nova.v1_1.util.NovaUtils;
|
import org.jclouds.util.Multimaps2;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMultimap;
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
@ -141,7 +141,7 @@ public class Server extends Resource {
|
||||||
|
|
||||||
protected Server(String id, String name, Set<Link> links, Multimap<Address.Type, Address> addresses) {
|
protected Server(String id, String name, Set<Link> links, Multimap<Address.Type, Address> addresses) {
|
||||||
super(id, name, links);
|
super(id, name, links);
|
||||||
this.addresses = NovaUtils.toOldSchool(ImmutableMultimap.copyOf(checkNotNull(addresses, "addresses")));
|
this.addresses = Multimaps2.toOldSchool(ImmutableMultimap.copyOf(checkNotNull(addresses, "addresses")));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -162,7 +162,7 @@ public class Server extends Resource {
|
||||||
* @return the ip addresses assigned to the server
|
* @return the ip addresses assigned to the server
|
||||||
*/
|
*/
|
||||||
public Multimap<Type, Address> getAddresses() {
|
public Multimap<Type, Address> getAddresses() {
|
||||||
return NovaUtils.fromOldSchool(addresses);
|
return Multimaps2.fromOldSchool(addresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -21,7 +21,6 @@ package org.jclouds.rackspace.cloudloadbalancers;
|
||||||
import static org.jclouds.Constants.PROPERTY_API_VERSION;
|
import static org.jclouds.Constants.PROPERTY_API_VERSION;
|
||||||
import static org.jclouds.Constants.PROPERTY_ENDPOINT;
|
import static org.jclouds.Constants.PROPERTY_ENDPOINT;
|
||||||
import static org.jclouds.Constants.PROPERTY_ISO3166_CODES;
|
import static org.jclouds.Constants.PROPERTY_ISO3166_CODES;
|
||||||
import static org.jclouds.cloudloadbalancers.reference.RackspaceConstants.PROPERTY_ACCOUNT_ID;
|
|
||||||
import static org.jclouds.cloudloadbalancers.reference.Region.LON;
|
import static org.jclouds.cloudloadbalancers.reference.Region.LON;
|
||||||
import static org.jclouds.location.reference.LocationConstants.ENDPOINT;
|
import static org.jclouds.location.reference.LocationConstants.ENDPOINT;
|
||||||
import static org.jclouds.location.reference.LocationConstants.ISO3166_CODES;
|
import static org.jclouds.location.reference.LocationConstants.ISO3166_CODES;
|
||||||
|
@ -50,9 +49,8 @@ public class CloudLoadBalancersUKPropertiesBuilder extends CloudLoadBalancersPro
|
||||||
properties.setProperty(PROPERTY_ISO3166_CODES, "GB-SLG");
|
properties.setProperty(PROPERTY_ISO3166_CODES, "GB-SLG");
|
||||||
|
|
||||||
properties.setProperty(PROPERTY_REGION + "." + LON + "." + ISO3166_CODES, "GB-SLG");
|
properties.setProperty(PROPERTY_REGION + "." + LON + "." + ISO3166_CODES, "GB-SLG");
|
||||||
properties.setProperty(PROPERTY_REGION + "." + LON + "." + ENDPOINT, String
|
properties.setProperty(PROPERTY_REGION + "." + LON + "." + ENDPOINT,
|
||||||
.format("https://lon.loadbalancers.api.rackspacecloud.com/v{%s}/{%s}", PROPERTY_API_VERSION,
|
String.format("https://lon.loadbalancers.api.rackspacecloud.com/v${%s}", PROPERTY_API_VERSION));
|
||||||
PROPERTY_ACCOUNT_ID));
|
|
||||||
|
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ package org.jclouds.rackspace.cloudloadbalancers;
|
||||||
import static org.jclouds.Constants.PROPERTY_API_VERSION;
|
import static org.jclouds.Constants.PROPERTY_API_VERSION;
|
||||||
import static org.jclouds.Constants.PROPERTY_ENDPOINT;
|
import static org.jclouds.Constants.PROPERTY_ENDPOINT;
|
||||||
import static org.jclouds.Constants.PROPERTY_ISO3166_CODES;
|
import static org.jclouds.Constants.PROPERTY_ISO3166_CODES;
|
||||||
import static org.jclouds.cloudloadbalancers.reference.RackspaceConstants.PROPERTY_ACCOUNT_ID;
|
|
||||||
import static org.jclouds.cloudloadbalancers.reference.Region.DFW;
|
import static org.jclouds.cloudloadbalancers.reference.Region.DFW;
|
||||||
import static org.jclouds.cloudloadbalancers.reference.Region.ORD;
|
import static org.jclouds.cloudloadbalancers.reference.Region.ORD;
|
||||||
import static org.jclouds.location.reference.LocationConstants.ENDPOINT;
|
import static org.jclouds.location.reference.LocationConstants.ENDPOINT;
|
||||||
|
@ -52,13 +51,11 @@ public class CloudLoadBalancersUSPropertiesBuilder extends CloudLoadBalancersPro
|
||||||
|
|
||||||
properties.setProperty(PROPERTY_REGION + "." + ORD + "." + ISO3166_CODES, "US-IL");
|
properties.setProperty(PROPERTY_REGION + "." + ORD + "." + ISO3166_CODES, "US-IL");
|
||||||
properties.setProperty(PROPERTY_REGION + "." + ORD + "." + ENDPOINT, String
|
properties.setProperty(PROPERTY_REGION + "." + ORD + "." + ENDPOINT, String
|
||||||
.format("https://ord.loadbalancers.api.rackspacecloud.com/v{%s}/{%s}", PROPERTY_API_VERSION,
|
.format("https://ord.loadbalancers.api.rackspacecloud.com/v${%s}", PROPERTY_API_VERSION));
|
||||||
PROPERTY_ACCOUNT_ID));
|
|
||||||
|
|
||||||
properties.setProperty(PROPERTY_REGION + "." + DFW + "." + ISO3166_CODES, "US-TX");
|
properties.setProperty(PROPERTY_REGION + "." + DFW + "." + ISO3166_CODES, "US-TX");
|
||||||
properties.setProperty(PROPERTY_REGION + "." + DFW + "." + ENDPOINT, String
|
properties.setProperty(PROPERTY_REGION + "." + DFW + "." + ENDPOINT, String
|
||||||
.format("https://dfw.loadbalancers.api.rackspacecloud.com/v{%s}/{%s}", PROPERTY_API_VERSION,
|
.format("https://dfw.loadbalancers.api.rackspacecloud.com/v${%s}", PROPERTY_API_VERSION));
|
||||||
PROPERTY_ACCOUNT_ID));
|
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,8 +98,8 @@ public abstract class BaseVPDCAsyncClientTest<T> extends RestClientTest<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Properties getProperties() {
|
protected Properties setupProperties() {
|
||||||
Properties props = super.getProperties();
|
Properties props = super.setupProperties();
|
||||||
props.setProperty(VPDCConstants.PROPERTY_VPDC_VDC_EMAIL, "test");
|
props.setProperty(VPDCConstants.PROPERTY_VPDC_VDC_EMAIL, "test");
|
||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue