blob: 7bf1afd861277a687e7eff4ae3f8806275e8b71b [file] [log] [blame]
/**
* 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.cloudstack.config;
import static com.google.common.base.Throwables.propagate;
import static org.jclouds.rest.config.BinderUtils.bindClientAndAsyncClient;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import org.jclouds.Constants;
import org.jclouds.cloudstack.CloudStackAsyncClient;
import org.jclouds.cloudstack.CloudStackClient;
import org.jclouds.cloudstack.CloudStackDomainAsyncClient;
import org.jclouds.cloudstack.CloudStackDomainClient;
import org.jclouds.cloudstack.CloudStackGlobalAsyncClient;
import org.jclouds.cloudstack.CloudStackGlobalClient;
import org.jclouds.cloudstack.domain.LoginResponse;
import org.jclouds.cloudstack.features.AccountAsyncClient;
import org.jclouds.cloudstack.features.AccountClient;
import org.jclouds.cloudstack.features.AddressAsyncClient;
import org.jclouds.cloudstack.features.AddressClient;
import org.jclouds.cloudstack.features.AsyncJobAsyncClient;
import org.jclouds.cloudstack.features.AsyncJobClient;
import org.jclouds.cloudstack.features.ConfigurationAsyncClient;
import org.jclouds.cloudstack.features.ConfigurationClient;
import org.jclouds.cloudstack.features.DomainAccountAsyncClient;
import org.jclouds.cloudstack.features.DomainAccountClient;
import org.jclouds.cloudstack.features.DomainDomainAsyncClient;
import org.jclouds.cloudstack.features.DomainDomainClient;
import org.jclouds.cloudstack.features.DomainLimitAsyncClient;
import org.jclouds.cloudstack.features.DomainLimitClient;
import org.jclouds.cloudstack.features.DomainUserAsyncClient;
import org.jclouds.cloudstack.features.DomainUserClient;
import org.jclouds.cloudstack.features.EventAsyncClient;
import org.jclouds.cloudstack.features.EventClient;
import org.jclouds.cloudstack.features.FirewallAsyncClient;
import org.jclouds.cloudstack.features.FirewallClient;
import org.jclouds.cloudstack.features.GlobalAccountAsyncClient;
import org.jclouds.cloudstack.features.GlobalAccountClient;
import org.jclouds.cloudstack.features.GlobalAlertAsyncClient;
import org.jclouds.cloudstack.features.GlobalAlertClient;
import org.jclouds.cloudstack.features.GlobalCapacityAsyncClient;
import org.jclouds.cloudstack.features.GlobalCapacityClient;
import org.jclouds.cloudstack.features.GlobalConfigurationAsyncClient;
import org.jclouds.cloudstack.features.GlobalConfigurationClient;
import org.jclouds.cloudstack.features.GlobalDomainAsyncClient;
import org.jclouds.cloudstack.features.GlobalDomainClient;
import org.jclouds.cloudstack.features.GlobalHostAsyncClient;
import org.jclouds.cloudstack.features.GlobalHostClient;
import org.jclouds.cloudstack.features.GlobalOfferingAsyncClient;
import org.jclouds.cloudstack.features.GlobalOfferingClient;
import org.jclouds.cloudstack.features.GlobalPodAsyncClient;
import org.jclouds.cloudstack.features.GlobalPodClient;
import org.jclouds.cloudstack.features.GlobalStoragePoolAsyncClient;
import org.jclouds.cloudstack.features.GlobalStoragePoolClient;
import org.jclouds.cloudstack.features.GlobalUsageAsyncClient;
import org.jclouds.cloudstack.features.GlobalUsageClient;
import org.jclouds.cloudstack.features.GlobalUserAsyncClient;
import org.jclouds.cloudstack.features.GlobalUserClient;
import org.jclouds.cloudstack.features.GlobalVlanAsyncClient;
import org.jclouds.cloudstack.features.GlobalVlanClient;
import org.jclouds.cloudstack.features.GlobalZoneAsyncClient;
import org.jclouds.cloudstack.features.GlobalZoneClient;
import org.jclouds.cloudstack.features.GuestOSAsyncClient;
import org.jclouds.cloudstack.features.GuestOSClient;
import org.jclouds.cloudstack.features.HypervisorAsyncClient;
import org.jclouds.cloudstack.features.HypervisorClient;
import org.jclouds.cloudstack.features.ISOAsyncClient;
import org.jclouds.cloudstack.features.ISOClient;
import org.jclouds.cloudstack.features.LimitAsyncClient;
import org.jclouds.cloudstack.features.LimitClient;
import org.jclouds.cloudstack.features.LoadBalancerAsyncClient;
import org.jclouds.cloudstack.features.LoadBalancerClient;
import org.jclouds.cloudstack.features.NATAsyncClient;
import org.jclouds.cloudstack.features.NATClient;
import org.jclouds.cloudstack.features.NetworkAsyncClient;
import org.jclouds.cloudstack.features.NetworkClient;
import org.jclouds.cloudstack.features.OfferingAsyncClient;
import org.jclouds.cloudstack.features.OfferingClient;
import org.jclouds.cloudstack.features.SSHKeyPairAsyncClient;
import org.jclouds.cloudstack.features.SSHKeyPairClient;
import org.jclouds.cloudstack.features.SecurityGroupAsyncClient;
import org.jclouds.cloudstack.features.SecurityGroupClient;
import org.jclouds.cloudstack.features.SessionAsyncClient;
import org.jclouds.cloudstack.features.SessionClient;
import org.jclouds.cloudstack.features.SnapshotAsyncClient;
import org.jclouds.cloudstack.features.SnapshotClient;
import org.jclouds.cloudstack.features.TemplateAsyncClient;
import org.jclouds.cloudstack.features.TemplateClient;
import org.jclouds.cloudstack.features.VMGroupAsyncClient;
import org.jclouds.cloudstack.features.VMGroupClient;
import org.jclouds.cloudstack.features.VirtualMachineAsyncClient;
import org.jclouds.cloudstack.features.VirtualMachineClient;
import org.jclouds.cloudstack.features.VolumeAsyncClient;
import org.jclouds.cloudstack.features.VolumeClient;
import org.jclouds.cloudstack.features.ZoneAsyncClient;
import org.jclouds.cloudstack.features.ZoneClient;
import org.jclouds.cloudstack.filters.AddSessionKeyAndJSessionIdToRequest;
import org.jclouds.cloudstack.filters.AuthenticationFilter;
import org.jclouds.cloudstack.filters.QuerySigner;
import org.jclouds.cloudstack.functions.LoginWithPasswordCredentials;
import org.jclouds.cloudstack.handlers.CloudStackErrorHandler;
import org.jclouds.cloudstack.handlers.InvalidateSessionAndRetryOn401AndLogoutOnClose;
import org.jclouds.concurrent.RetryOnTimeOutExceptionFunction;
import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError;
import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.location.Provider;
import org.jclouds.location.suppliers.ImplicitLocationSupplier;
import org.jclouds.location.suppliers.implicit.OnlyLocationOrFirstZone;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.config.BinderUtils;
import org.jclouds.rest.config.RestClientModule;
import org.jclouds.rest.internal.RestContextImpl;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Inject;
import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.google.inject.name.Named;
/**
* Configures the cloudstack connection.
*
* @author Adrian Cole
*/
@ConfiguresRestClient
public class CloudStackRestClientModule extends RestClientModule<CloudStackClient, CloudStackAsyncClient> {
public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()//
.put(ZoneClient.class, ZoneAsyncClient.class)//
.put(GlobalZoneClient.class, GlobalZoneAsyncClient.class)//
.put(TemplateClient.class, TemplateAsyncClient.class)//
.put(OfferingClient.class, OfferingAsyncClient.class)//
.put(NetworkClient.class, NetworkAsyncClient.class)//
.put(VirtualMachineClient.class, VirtualMachineAsyncClient.class)//
.put(SecurityGroupClient.class, SecurityGroupAsyncClient.class)//
.put(AsyncJobClient.class, AsyncJobAsyncClient.class)//
.put(AddressClient.class, AddressAsyncClient.class)//
.put(NATClient.class, NATAsyncClient.class)//
.put(FirewallClient.class, FirewallAsyncClient.class)//
.put(LoadBalancerClient.class, LoadBalancerAsyncClient.class)//
.put(GuestOSClient.class, GuestOSAsyncClient.class)//
.put(HypervisorClient.class, HypervisorAsyncClient.class)//
.put(ConfigurationClient.class, ConfigurationAsyncClient.class)//
.put(GlobalConfigurationClient.class, GlobalConfigurationAsyncClient.class)//
.put(AccountClient.class, AccountAsyncClient.class)//
.put(DomainAccountClient.class, DomainAccountAsyncClient.class)//
.put(DomainUserClient.class, DomainUserAsyncClient.class)//
.put(DomainDomainClient.class, DomainDomainAsyncClient.class)//
.put(GlobalDomainClient.class, GlobalDomainAsyncClient.class)//
.put(GlobalAccountClient.class, GlobalAccountAsyncClient.class)//
.put(GlobalUserClient.class, GlobalUserAsyncClient.class)//
.put(EventClient.class, EventAsyncClient.class)//
.put(LimitClient.class, LimitAsyncClient.class)//
.put(DomainLimitClient.class, DomainLimitAsyncClient.class)//
.put(SSHKeyPairClient.class, SSHKeyPairAsyncClient.class)//
.put(VMGroupClient.class, VMGroupAsyncClient.class)//
.put(ISOClient.class, ISOAsyncClient.class)//
.put(VolumeClient.class, VolumeAsyncClient.class)//
.put(SnapshotClient.class, SnapshotAsyncClient.class)//
.put(GlobalAlertClient.class, GlobalAlertAsyncClient.class)//
.put(GlobalCapacityClient.class, GlobalCapacityAsyncClient.class)//
.put(GlobalOfferingClient.class, GlobalOfferingAsyncClient.class)//
.put(GlobalHostClient.class, GlobalHostAsyncClient.class)//
.put(GlobalStoragePoolClient.class, GlobalStoragePoolAsyncClient.class)//
.put(GlobalUsageClient.class, GlobalUsageAsyncClient.class)//
.put(GlobalPodClient.class, GlobalPodAsyncClient.class)//
.put(GlobalVlanClient.class, GlobalVlanAsyncClient.class)//
.put(SessionClient.class, SessionAsyncClient.class)//
.build();
@Override
protected void bindAsyncClient() {
// bind the user client (default)
super.bindAsyncClient();
// bind the domain admin client
BinderUtils.bindAsyncClient(binder(), CloudStackDomainAsyncClient.class);
// bind the global admin client
BinderUtils.bindAsyncClient(binder(), CloudStackGlobalAsyncClient.class);
}
@Override
protected void bindClient() {
// bind the user client (default)
super.bindClient();
// bind the domain admin client
BinderUtils.bindClient(binder(), CloudStackDomainClient.class, CloudStackDomainAsyncClient.class, DELEGATE_MAP);
// bind the domain admin client
BinderUtils.bindClient(binder(), CloudStackGlobalClient.class, CloudStackGlobalAsyncClient.class, DELEGATE_MAP);
}
public CloudStackRestClientModule() {
super(DELEGATE_MAP);
}
@Override
protected void configure() {
bind(DateAdapter.class).to(CloudStackDateAdapter.class);
bind(new TypeLiteral<RestContext<CloudStackDomainClient, CloudStackDomainAsyncClient>>() {
}).to(new TypeLiteral<RestContextImpl<CloudStackDomainClient, CloudStackDomainAsyncClient>>() {
});
bind(new TypeLiteral<RestContext<CloudStackGlobalClient, CloudStackGlobalAsyncClient>>() {
}).to(new TypeLiteral<RestContextImpl<CloudStackGlobalClient, CloudStackGlobalAsyncClient>>() {
});
install(new CloudStackParserModule());
bind(CredentialType.class).toProvider(CredentialTypeFromPropertyOrDefault.class);
// session client is used directly for filters and retry handlers, so let's bind it explicitly
bindClientAndAsyncClient(binder(), SessionClient.class, SessionAsyncClient.class);
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(InvalidateSessionAndRetryOn401AndLogoutOnClose.class);
super.configure();
}
@Override
protected void installLocations() {
super.installLocations();
bind(ImplicitLocationSupplier.class).to(OnlyLocationOrFirstZone.class).in(Scopes.SINGLETON);
}
@Override
protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(CloudStackErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(CloudStackErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(CloudStackErrorHandler.class);
}
@Singleton
static class CredentialTypeFromPropertyOrDefault implements javax.inject.Provider<CredentialType> {
/**
* use optional injection to supply a default value for credential type. so that we don't have
* to set a default property.
*/
@Inject(optional = true)
@Named(CloudStackProperties.CREDENTIAL_TYPE)
String credentialType = CredentialType.API_ACCESS_KEY_CREDENTIALS.toString();
@Override
public CredentialType get() {
return CredentialType.fromValue(credentialType);
}
}
/**
* we use the type of credentials specified at login to determine which way we want to filter the
* request. <br/>
* for ex, if we are getting passwords, we know we will need to login/logout. Otherwise we are
* signing requests.
*/
@Provides
@Singleton
protected AuthenticationFilter authenticationFilterForCredentialType(CredentialType credentialType,
AddSessionKeyAndJSessionIdToRequest addSessionKeyAndJSessionIdToRequest, QuerySigner querySigner) {
switch (credentialType) {
case PASSWORD_CREDENTIALS:
return addSessionKeyAndJSessionIdToRequest;
case API_ACCESS_KEY_CREDENTIALS:
return querySigner;
default:
throw new IllegalArgumentException("credential type not supported: " + credentialType);
}
}
@Provides
@Singleton
protected Function<Credentials, LoginResponse> makeSureFilterRetriesOnTimeout(
LoginWithPasswordCredentials loginWithPasswordCredentials) {
// we should retry on timeout exception logging in.
return new RetryOnTimeOutExceptionFunction<Credentials, LoginResponse>(loginWithPasswordCredentials);
}
// TODO: not sure we can action the timeout from loginresponse without extra code? modify default
// accordingly
// PROPERTY_SESSION_INTERVAL is default to 60 seconds
@Provides
@Singleton
public LoadingCache<Credentials, LoginResponse> provideLoginResponseCache(
Function<Credentials, LoginResponse> getLoginResponse,
@Named(Constants.PROPERTY_SESSION_INTERVAL) int seconds) {
return CacheBuilder.newBuilder().expireAfterWrite(seconds, TimeUnit.SECONDS).build(
CacheLoader.from(getLoginResponse));
}
// Temporary conversion of a cache to a supplier until there is a single-element cache
// http://code.google.com/p/guava-libraries/issues/detail?id=872
@Provides
@Singleton
protected Supplier<LoginResponse> provideLoginResponseSupplier(final LoadingCache<Credentials, LoginResponse> cache,
@Provider final Credentials creds) {
return new Supplier<LoginResponse>() {
@Override
public LoginResponse get() {
try {
return cache.get(creds);
} catch (ExecutionException e) {
throw propagate(e.getCause());
}
}
};
}
}