mirror of https://github.com/apache/jclouds.git
Issue 690:Update to guava 10.0rc2 and change from MapMaker to CacheBuilder
This commit is contained in:
parent
d039fe7d96
commit
4cd94489c9
|
@ -25,9 +25,6 @@ import static org.jclouds.tools.ant.taskdefs.compute.ComputeTaskUtils.ipOrEmptyS
|
|||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
|
||||
import org.apache.tools.ant.BuildException;
|
||||
import org.apache.tools.ant.Project;
|
||||
|
@ -43,10 +40,12 @@ import org.jclouds.compute.domain.Template;
|
|||
import org.jclouds.compute.predicates.NodePredicates;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
import org.jclouds.util.CredentialUtils;
|
||||
|
||||
import com.google.common.base.CaseFormat;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
|
@ -56,7 +55,7 @@ import com.google.inject.Provider;
|
|||
*/
|
||||
public class ComputeTask extends Task {
|
||||
|
||||
private final Map<URI, ComputeServiceContext> computeMap;
|
||||
private final Cache<URI, ComputeServiceContext> computeMap;
|
||||
private String provider;
|
||||
private String actions;
|
||||
private NodeElement nodeElement;
|
||||
|
@ -72,7 +71,7 @@ public class ComputeTask extends Task {
|
|||
}
|
||||
};
|
||||
|
||||
public ComputeTask(@Nullable Map<URI, ComputeServiceContext> computeMap) {
|
||||
public ComputeTask(@Nullable Cache<URI, ComputeServiceContext> computeMap) {
|
||||
this.computeMap = computeMap != null ? computeMap : buildComputeMap(projectProvider);
|
||||
}
|
||||
|
||||
|
@ -88,7 +87,7 @@ public class ComputeTask extends Task {
|
|||
* makes a connection to the compute service and invokes
|
||||
*/
|
||||
public void execute() throws BuildException {
|
||||
ComputeServiceContext context = computeMap.get(HttpUtils.createUri(provider));
|
||||
ComputeServiceContext context = computeMap.getUnchecked(HttpUtils.createUri(provider));
|
||||
|
||||
try {
|
||||
for (String action : Splitter.on(',').split(actions)) {
|
||||
|
|
|
@ -22,7 +22,6 @@ import static org.jclouds.rest.RestContextFactory.getPropertiesFromResource;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
@ -43,11 +42,12 @@ import org.jclouds.ssh.jsch.config.JschSshClientModule;
|
|||
import org.jclouds.tools.ant.logging.config.AntLoggingModule;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.Provider;
|
||||
|
@ -67,12 +67,12 @@ public class ComputeTaskUtils {
|
|||
* allows access to the ant project to retrieve default properties needed for compute
|
||||
* providers.
|
||||
*/
|
||||
static Map<URI, ComputeServiceContext> buildComputeMap(final Provider<Project> projectProvider) {
|
||||
return new MapMaker().makeComputingMap(new Function<URI, ComputeServiceContext>() {
|
||||
static Cache<URI, ComputeServiceContext> buildComputeMap(final Provider<Project> projectProvider) {
|
||||
return CacheBuilder.newBuilder().build(new CacheLoader<URI, ComputeServiceContext>() {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ComputeServiceContext apply(URI from) {
|
||||
public ComputeServiceContext load(URI from) {
|
||||
Properties props = getPropertiesFromResource("/rest.properties");
|
||||
props.putAll(projectProvider.get().getProperties());
|
||||
// adding the properties to the factory will allow us to pass
|
||||
|
|
|
@ -68,6 +68,7 @@ import com.google.common.annotations.VisibleForTesting;
|
|||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableMultimap.Builder;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
@ -78,8 +79,8 @@ import com.google.common.collect.ImmutableSet;
|
|||
@Singleton
|
||||
public class EC2ComputeService extends BaseComputeService {
|
||||
private final EC2Client ec2Client;
|
||||
private final Map<RegionAndName, KeyPair> credentialsMap;
|
||||
private final Map<RegionAndName, String> securityGroupMap;
|
||||
private final Cache<RegionAndName, KeyPair> credentialsMap;
|
||||
private final Cache<RegionAndName, String> securityGroupMap;
|
||||
|
||||
@Inject
|
||||
protected EC2ComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore,
|
||||
|
@ -96,7 +97,7 @@ public class EC2ComputeService extends BaseComputeService {
|
|||
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
|
||||
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, EC2Client ec2Client,
|
||||
Map<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") Map<RegionAndName, String> securityGroupMap) {
|
||||
Cache<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") Cache<RegionAndName, String> securityGroupMap) {
|
||||
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
|
||||
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy,
|
||||
templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, nodeSuspended,
|
||||
|
@ -116,7 +117,7 @@ public class EC2ComputeService extends BaseComputeService {
|
|||
try {
|
||||
ec2Client.getSecurityGroupServices().deleteSecurityGroupInRegion(region, groupName);
|
||||
// TODO: test this clear happens
|
||||
securityGroupMap.remove(new RegionNameAndIngressRules(region, groupName, null, false));
|
||||
securityGroupMap.invalidate(new RegionNameAndIngressRules(region, groupName, null, false));
|
||||
logger.debug("<< deleted securityGroup(%s)", groupName);
|
||||
} catch (IllegalStateException e) {
|
||||
logger.debug("<< inUse securityGroup(%s)", groupName);
|
||||
|
@ -142,7 +143,7 @@ public class EC2ComputeService extends BaseComputeService {
|
|||
logger.debug(">> deleting keyPair(%s)", keyPair.getKeyName());
|
||||
ec2Client.getKeyPairServices().deleteKeyPairInRegion(region, keyPair.getKeyName());
|
||||
// TODO: test this clear happens
|
||||
credentialsMap.remove(new RegionAndName(region, keyPair.getKeyName()));
|
||||
credentialsMap.invalidate(new RegionAndName(region, keyPair.getKeyName()));
|
||||
logger.debug("<< deleted keyPair(%s)", keyPair.getKeyName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,6 @@ import static com.google.common.collect.Iterables.toArray;
|
|||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||
import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_AMI_OWNERS;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
|
@ -37,6 +35,7 @@ import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExc
|
|||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.inject.Provides;
|
||||
|
||||
/**
|
||||
|
@ -59,12 +58,12 @@ public class EC2ComputeServiceContextModule extends BaseComputeServiceContextMod
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected Supplier<Map<RegionAndName, ? extends Image>> provideRegionAndNameToImageSupplierCache(
|
||||
protected Supplier<Cache<RegionAndName, ? extends Image>> provideRegionAndNameToImageSupplierCache(
|
||||
@Named(PROPERTY_SESSION_INTERVAL) long seconds, final RegionAndNameToImageSupplier supplier) {
|
||||
return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<RegionAndName, ? extends Image>>(
|
||||
authException, seconds, new Supplier<Map<RegionAndName, ? extends Image>>() {
|
||||
return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Cache<RegionAndName, ? extends Image>>(
|
||||
authException, seconds, new Supplier<Cache<RegionAndName, ? extends Image>>() {
|
||||
@Override
|
||||
public Map<RegionAndName, ? extends Image> get() {
|
||||
public Cache<RegionAndName, ? extends Image> get() {
|
||||
return supplier.get();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.ec2.compute.config;
|
||||
|
||||
import static com.google.common.collect.Maps.newLinkedHashMap;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -39,7 +37,6 @@ import org.jclouds.ec2.EC2AsyncClient;
|
|||
import org.jclouds.ec2.EC2Client;
|
||||
import org.jclouds.ec2.compute.EC2ComputeService;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.ec2.compute.domain.RegionNameAndIngressRules;
|
||||
import org.jclouds.ec2.compute.functions.CreateSecurityGroupIfNeeded;
|
||||
import org.jclouds.ec2.compute.functions.CreateUniqueKeyPair;
|
||||
import org.jclouds.ec2.compute.functions.CredentialsForInstance;
|
||||
|
@ -55,8 +52,11 @@ import org.jclouds.rest.internal.RestContextImpl;
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.Scopes;
|
||||
|
@ -69,11 +69,11 @@ import com.google.inject.TypeLiteral;
|
|||
public class EC2ComputeServiceDependenciesModule extends AbstractModule {
|
||||
|
||||
public static final Map<InstanceState, NodeState> instanceToNodeState = ImmutableMap
|
||||
.<InstanceState, NodeState> builder().put(InstanceState.PENDING, NodeState.PENDING).put(
|
||||
InstanceState.RUNNING, NodeState.RUNNING).put(InstanceState.SHUTTING_DOWN, NodeState.PENDING).put(
|
||||
InstanceState.TERMINATED, NodeState.TERMINATED).put(InstanceState.STOPPING, NodeState.PENDING)
|
||||
.put(InstanceState.STOPPED, NodeState.SUSPENDED).put(InstanceState.UNRECOGNIZED, NodeState.UNRECOGNIZED)
|
||||
.build();
|
||||
.<InstanceState, NodeState> builder().put(InstanceState.PENDING, NodeState.PENDING)
|
||||
.put(InstanceState.RUNNING, NodeState.RUNNING).put(InstanceState.SHUTTING_DOWN, NodeState.PENDING)
|
||||
.put(InstanceState.TERMINATED, NodeState.TERMINATED).put(InstanceState.STOPPING, NodeState.PENDING)
|
||||
.put(InstanceState.STOPPED, NodeState.SUSPENDED).put(InstanceState.UNRECOGNIZED, NodeState.UNRECOGNIZED)
|
||||
.build();
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
|
@ -88,13 +88,13 @@ public class EC2ComputeServiceDependenciesModule extends AbstractModule {
|
|||
bind(ComputeService.class).to(EC2ComputeService.class);
|
||||
bind(new TypeLiteral<Function<RunningInstance, NodeMetadata>>() {
|
||||
}).to(RunningInstanceToNodeMetadata.class);
|
||||
bind(new TypeLiteral<Function<RunningInstance, Credentials>>() {
|
||||
bind(new TypeLiteral<CacheLoader<RunningInstance, Credentials>>() {
|
||||
}).to(CredentialsForInstance.class);
|
||||
bind(new TypeLiteral<Function<RegionNameAndIngressRules, String>>() {
|
||||
bind(new TypeLiteral<CacheLoader<RegionAndName, String>>() {
|
||||
}).to(CreateSecurityGroupIfNeeded.class);
|
||||
bind(new TypeLiteral<Function<RegionAndName, KeyPair>>() {
|
||||
bind(new TypeLiteral<CacheLoader<RegionAndName, KeyPair>>() {
|
||||
}).to(CreateUniqueKeyPair.class);
|
||||
bind(new TypeLiteral<Function<RegionAndName, Image>>() {
|
||||
bind(new TypeLiteral<CacheLoader<RegionAndName, Image>>() {
|
||||
}).to(RegionAndIdToImage.class);
|
||||
bind(new TypeLiteral<ComputeServiceContext>() {
|
||||
}).to(new TypeLiteral<ComputeServiceContextImpl<EC2Client, EC2AsyncClient>>() {
|
||||
|
@ -120,25 +120,35 @@ public class EC2ComputeServiceDependenciesModule extends AbstractModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected final Map<RegionAndName, KeyPair> credentialsMap(Function<RegionAndName, KeyPair> in) {
|
||||
// doesn't seem to clear when someone issues remove(key)
|
||||
// return new MapMaker().makeComputingMap(in);
|
||||
return newLinkedHashMap();
|
||||
protected Cache<RunningInstance, Credentials> credentialsMap(CacheLoader<RunningInstance, Credentials> in) {
|
||||
return CacheBuilder.newBuilder().build(in);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected Cache<RegionAndName, KeyPair> keypairMap(CacheLoader<RegionAndName, KeyPair> in) {
|
||||
return CacheBuilder.newBuilder().build(in);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
// keys that we know about.
|
||||
protected Map<RegionAndName, KeyPair> knownKeys(){
|
||||
return Maps.newConcurrentMap();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("SECURITY")
|
||||
protected final Map<RegionAndName, String> securityGroupMap(Function<RegionNameAndIngressRules, String> in) {
|
||||
// doesn't seem to clear when someone issues remove(key)
|
||||
// return new MapMaker().makeComputingMap(in);
|
||||
return newLinkedHashMap();
|
||||
protected Cache<RegionAndName, String> securityGroupMap(CacheLoader<RegionAndName, String> in) {
|
||||
return CacheBuilder.newBuilder().build(in);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected Map<RegionAndName, Image> provideImageMap(Function<RegionAndName, Image> regionAndIdToImage) {
|
||||
return new MapMaker().makeComputingMap(regionAndIdToImage);
|
||||
// keys that we know about.
|
||||
protected Map<RegionAndName, Image> knownImages(){
|
||||
return Maps.newConcurrentMap();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,14 +25,15 @@ import javax.inject.Inject;
|
|||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.ec2.EC2Client;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.ec2.compute.domain.RegionNameAndIngressRules;
|
||||
import org.jclouds.ec2.domain.IpProtocol;
|
||||
import org.jclouds.ec2.domain.UserIdGroupPair;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.logging.Logger;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
|
@ -40,7 +41,7 @@ import com.google.common.collect.Iterables;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class CreateSecurityGroupIfNeeded implements Function<RegionNameAndIngressRules, String> {
|
||||
public class CreateSecurityGroupIfNeeded extends CacheLoader<RegionAndName, String> {
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
@ -52,8 +53,9 @@ public class CreateSecurityGroupIfNeeded implements Function<RegionNameAndIngres
|
|||
}
|
||||
|
||||
@Override
|
||||
public String apply(RegionNameAndIngressRules from) {
|
||||
createSecurityGroupInRegion(from.getRegion(), from.getName(), from.getPorts());
|
||||
public String load(RegionAndName from) {
|
||||
RegionNameAndIngressRules realFrom = RegionNameAndIngressRules.class.cast(from);
|
||||
createSecurityGroupInRegion(from.getRegion(), from.getName(), realFrom.getPorts());
|
||||
return from.getName();
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ package org.jclouds.ec2.compute.functions;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
@ -32,30 +34,33 @@ import org.jclouds.ec2.domain.KeyPair;
|
|||
import org.jclouds.logging.Logger;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class CreateUniqueKeyPair implements Function<RegionAndName, KeyPair> {
|
||||
public class CreateUniqueKeyPair extends CacheLoader<RegionAndName, KeyPair> {
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
protected final EC2Client ec2Client;
|
||||
protected final Supplier<String> randomSuffix;
|
||||
protected final Map<RegionAndName, KeyPair> knownKeys;
|
||||
|
||||
@Inject
|
||||
public CreateUniqueKeyPair(EC2Client ec2Client, Supplier<String> randomSuffix) {
|
||||
public CreateUniqueKeyPair(Map<RegionAndName, KeyPair> knownKeys, EC2Client ec2Client, Supplier<String> randomSuffix) {
|
||||
this.knownKeys = knownKeys;
|
||||
this.ec2Client = ec2Client;
|
||||
this.randomSuffix = randomSuffix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyPair apply(RegionAndName from) {
|
||||
return createNewKeyPairInRegion(from.getRegion(), from.getName());
|
||||
public KeyPair load(RegionAndName from) {
|
||||
return knownKeys.containsKey(from) ? knownKeys.get(from) : createNewKeyPairInRegion(from.getRegion(),
|
||||
from.getName());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
|
|
@ -20,43 +20,44 @@ package org.jclouds.ec2.compute.functions;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.ec2.domain.KeyPair;
|
||||
import org.jclouds.ec2.domain.RunningInstance;
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.ec2.domain.KeyPair;
|
||||
import org.jclouds.ec2.domain.RunningInstance;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class CredentialsForInstance implements Function<RunningInstance, Credentials> {
|
||||
private final Map<RegionAndName, KeyPair> credentialsMap;
|
||||
public class CredentialsForInstance extends CacheLoader<RunningInstance, Credentials> {
|
||||
private final Cache<RegionAndName, KeyPair> credentialsMap;
|
||||
private final PopulateDefaultLoginCredentialsForImageStrategy credentialProvider;
|
||||
private final Map<RegionAndName, Image> imageForInstance;
|
||||
private final Supplier<Cache<RegionAndName, ? extends Image>> imageMap;
|
||||
|
||||
@Inject
|
||||
CredentialsForInstance(Map<RegionAndName, KeyPair> credentialsMap,
|
||||
PopulateDefaultLoginCredentialsForImageStrategy credentialProvider, Map<RegionAndName, Image> imageForInstance) {
|
||||
CredentialsForInstance(Cache<RegionAndName, KeyPair> credentialsMap,
|
||||
PopulateDefaultLoginCredentialsForImageStrategy credentialProvider, Supplier<Cache<RegionAndName, ? extends Image>> imageMap) {
|
||||
this.credentialsMap = checkNotNull(credentialsMap, "credentialsMap");
|
||||
this.credentialProvider = checkNotNull(credentialProvider, "credentialProvider");
|
||||
this.imageForInstance = imageForInstance;
|
||||
this.imageMap = imageMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Credentials apply(RunningInstance instance) {
|
||||
public Credentials load(RunningInstance instance) throws ExecutionException {
|
||||
Credentials credentials = null;// default if no keypair exists
|
||||
|
||||
if (instance.getKeyName() != null) {
|
||||
credentials = new Credentials(getLoginAccountFor(instance), getPrivateKeyOrNull(instance));
|
||||
}
|
||||
|
@ -64,15 +65,15 @@ public class CredentialsForInstance implements Function<RunningInstance, Credent
|
|||
}
|
||||
|
||||
@VisibleForTesting
|
||||
String getPrivateKeyOrNull(RunningInstance instance) {
|
||||
String getPrivateKeyOrNull(RunningInstance instance) throws ExecutionException {
|
||||
KeyPair keyPair = credentialsMap.get(new RegionAndName(instance.getRegion(), instance.getKeyName()));
|
||||
return keyPair != null ? keyPair.getKeyMaterial() : null;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
String getLoginAccountFor(RunningInstance from) {
|
||||
String getLoginAccountFor(RunningInstance from) throws ExecutionException {
|
||||
return checkNotNull(
|
||||
credentialProvider.execute(imageForInstance.get(new RegionAndName(from.getRegion(), from.getImageId()))),
|
||||
credentialProvider.execute(imageMap.get().get(new RegionAndName(from.getRegion(), from.getImageId()))),
|
||||
"login from image: " + from.getImageId()).identity;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,19 +20,19 @@ package org.jclouds.ec2.compute.functions;
|
|||
|
||||
import static org.jclouds.ec2.options.DescribeImagesOptions.Builder.imageIds;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.ec2.EC2Client;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
|
@ -40,33 +40,31 @@ import com.google.common.collect.Iterables;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public final class RegionAndIdToImage implements Function<RegionAndName, Image> {
|
||||
public class RegionAndIdToImage extends CacheLoader<RegionAndName, Image> {
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private final Map<RegionAndName, Image> knownImages;
|
||||
private final EC2ImageParser parser;
|
||||
private final EC2Client sync;
|
||||
|
||||
@Inject
|
||||
public RegionAndIdToImage(EC2ImageParser parser, EC2Client sync) {
|
||||
public RegionAndIdToImage(Map<RegionAndName, Image> knownImages, EC2ImageParser parser, EC2Client sync) {
|
||||
this.knownImages = knownImages;
|
||||
this.parser = parser;
|
||||
this.sync = sync;
|
||||
}
|
||||
|
||||
public Image apply(RegionAndName key) {
|
||||
@Override
|
||||
public Image load(RegionAndName key) throws ExecutionException{
|
||||
if (knownImages.containsKey(key))
|
||||
return knownImages.get(key);
|
||||
try {
|
||||
org.jclouds.ec2.domain.Image image = Iterables.getOnlyElement(sync.getAMIServices()
|
||||
.describeImagesInRegion(key.getRegion(), imageIds(key.getName())));
|
||||
return parser.apply(image);
|
||||
} catch (NoSuchElementException e) {
|
||||
logger.debug(message(key, e));
|
||||
return null;
|
||||
} catch (ResourceNotFoundException e) {
|
||||
logger.debug(message(key, e));
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
logger.warn(e, message(key, e));
|
||||
return null;
|
||||
throw new ExecutionException(message(key, e), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,11 +30,6 @@ import javax.annotation.Resource;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.ec2.domain.BlockDevice;
|
||||
import org.jclouds.ec2.domain.InstanceState;
|
||||
import org.jclouds.ec2.domain.RootDeviceType;
|
||||
import org.jclouds.ec2.domain.RunningInstance;
|
||||
import org.jclouds.collect.Memoized;
|
||||
import org.jclouds.compute.domain.Hardware;
|
||||
import org.jclouds.compute.domain.HardwareBuilder;
|
||||
|
@ -46,6 +41,11 @@ import org.jclouds.compute.domain.Volume;
|
|||
import org.jclouds.compute.domain.internal.VolumeImpl;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.ec2.domain.BlockDevice;
|
||||
import org.jclouds.ec2.domain.InstanceState;
|
||||
import org.jclouds.ec2.domain.RootDeviceType;
|
||||
import org.jclouds.ec2.domain.RunningInstance;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.util.NullSafeCollections;
|
||||
|
||||
|
@ -53,8 +53,10 @@ import com.google.common.annotations.VisibleForTesting;
|
|||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
|
@ -67,17 +69,17 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
|
|||
|
||||
protected final Supplier<Set<? extends Location>> locations;
|
||||
protected final Supplier<Set<? extends Hardware>> hardware;
|
||||
protected final Map<RegionAndName, Image> instanceToImage;
|
||||
protected final Supplier<Cache<RegionAndName, ? extends Image>> imageMap;
|
||||
protected final Map<String, Credentials> credentialStore;
|
||||
protected final Map<InstanceState, NodeState> instanceToNodeState;
|
||||
|
||||
@Inject
|
||||
protected RunningInstanceToNodeMetadata(Map<InstanceState, NodeState> instanceToNodeState,
|
||||
Map<String, Credentials> credentialStore, Map<RegionAndName, Image> instanceToImage,
|
||||
Map<String, Credentials> credentialStore, Supplier<Cache<RegionAndName, ? extends Image>> imageMap,
|
||||
@Memoized Supplier<Set<? extends Location>> locations, @Memoized Supplier<Set<? extends Hardware>> hardware) {
|
||||
this.locations = checkNotNull(locations, "locations");
|
||||
this.hardware = checkNotNull(hardware, "hardware");
|
||||
this.instanceToImage = checkNotNull(instanceToImage, "instanceToImage");
|
||||
this.imageMap = checkNotNull(imageMap, "imageMap");
|
||||
this.instanceToNodeState = checkNotNull(instanceToNodeState, "instanceToNodeState");
|
||||
this.credentialStore = checkNotNull(credentialStore, "credentialStore");
|
||||
}
|
||||
|
@ -106,17 +108,13 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
|
|||
// extract the operating system from the image
|
||||
RegionAndName regionAndName = new RegionAndName(instance.getRegion(), instance.getImageId());
|
||||
try {
|
||||
Image image = instanceToImage.get(regionAndName);
|
||||
Image image = imageMap.get().getUnchecked(regionAndName);
|
||||
if (image != null)
|
||||
builder.operatingSystem(image.getOperatingSystem());
|
||||
} catch (NullPointerException e) {
|
||||
// The instanceToImage Map may throw NullPointerException (actually subclass
|
||||
// NullOutputException) if the
|
||||
// computing Function returns a null value.
|
||||
//
|
||||
// See the following for more information:
|
||||
// MapMaker.makeComputingMap()
|
||||
// RegionAndIdToImage.apply()
|
||||
logger.debug("image not found for %s: %s", regionAndName, e);
|
||||
} catch (UncheckedExecutionException e) {
|
||||
logger.debug("error getting image for %s: %s", regionAndName, e);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
|
|
|
@ -20,9 +20,9 @@ package org.jclouds.ec2.compute.internal;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
@ -38,7 +38,8 @@ import org.jclouds.domain.Location;
|
|||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ComputationException;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -46,13 +47,13 @@ import com.google.common.collect.ComputationException;
|
|||
*/
|
||||
public class EC2TemplateBuilderImpl extends TemplateBuilderImpl {
|
||||
|
||||
private final Map<RegionAndName, Image> imageMap;
|
||||
private final Supplier<Cache<RegionAndName, ? extends Image>> imageMap;
|
||||
|
||||
@Inject
|
||||
protected EC2TemplateBuilderImpl(@Memoized Supplier<Set<? extends Location>> locations,
|
||||
@Memoized Supplier<Set<? extends Image>> images, @Memoized Supplier<Set<? extends Hardware>> sizes,
|
||||
Supplier<Location> defaultLocation, @Named("DEFAULT") Provider<TemplateOptions> optionsProvider,
|
||||
@Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider, Map<RegionAndName, Image> imageMap) {
|
||||
@Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider, Supplier<Cache<RegionAndName, ? extends Image>> imageMap) {
|
||||
super(locations, images, sizes, defaultLocation, optionsProvider, defaultTemplateProvider);
|
||||
this.imageMap = imageMap;
|
||||
}
|
||||
|
@ -67,11 +68,13 @@ public class EC2TemplateBuilderImpl extends TemplateBuilderImpl {
|
|||
"amazon image ids must include the region ( ex. us-east-1/ami-7ea24a17 ) you specified: " + imageId);
|
||||
RegionAndName key = new RegionAndName(regionName[0], regionName[1]);
|
||||
try {
|
||||
return imageMap.get(key);
|
||||
return imageMap.get().get(key);
|
||||
} catch (ExecutionException e) {
|
||||
throw new NoSuchElementException(String.format("could not get imageId(%s/%s)", key.getRegion(), key.getName()));
|
||||
} catch (UncheckedExecutionException e) {
|
||||
throw new NoSuchElementException(String.format("could not get imageId(%s/%s)", key.getRegion(), key.getName()));
|
||||
} catch (NullPointerException nex) {
|
||||
throw new NoSuchElementException(String.format("imageId(%s/%s) not found", key.getRegion(), key.getName()));
|
||||
} catch (ComputationException nex) {
|
||||
throw new NoSuchElementException(String.format("imageId(%s/%s) not found", key.getRegion(), key.getName()));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -23,7 +23,6 @@ import static com.google.common.base.Preconditions.checkState;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
|
@ -37,11 +36,13 @@ import org.jclouds.ec2.compute.options.EC2TemplateOptions;
|
|||
import org.jclouds.ec2.domain.BlockDeviceMapping;
|
||||
import org.jclouds.ec2.domain.KeyPair;
|
||||
import org.jclouds.ec2.options.RunInstancesOptions;
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSet.Builder;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -49,26 +50,21 @@ import com.google.common.collect.ImmutableSet.Builder;
|
|||
*/
|
||||
@Singleton
|
||||
public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions {
|
||||
|
||||
@VisibleForTesting
|
||||
public final Map<RegionAndName, KeyPair> credentialsMap;
|
||||
public final Map<RegionAndName, KeyPair> knownKeys;
|
||||
@VisibleForTesting
|
||||
public final Map<RegionAndName, String> securityGroupMap;
|
||||
public final Cache<RegionAndName, KeyPair> credentialsMap;
|
||||
@VisibleForTesting
|
||||
public final Function<RegionAndName, KeyPair> createUniqueKeyPair;
|
||||
@VisibleForTesting
|
||||
public final Function<RegionNameAndIngressRules, String> createSecurityGroupIfNeeded;
|
||||
public final Cache<RegionAndName, String> securityGroupMap;
|
||||
protected final Provider<RunInstancesOptions> optionsProvider;
|
||||
|
||||
@Inject
|
||||
public CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions(Map<RegionAndName, KeyPair> credentialsMap,
|
||||
@Named("SECURITY") Map<RegionAndName, String> securityGroupMap, Function<RegionAndName, KeyPair> createUniqueKeyPair,
|
||||
Function<RegionNameAndIngressRules, String> createSecurityGroupIfNeeded,
|
||||
public CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions(Map<RegionAndName, KeyPair> knownKeys, Cache<RegionAndName, KeyPair> credentialsMap,
|
||||
@Named("SECURITY") Cache<RegionAndName, String> securityGroupMap,
|
||||
Provider<RunInstancesOptions> optionsProvider) {
|
||||
this.knownKeys=knownKeys;
|
||||
this.credentialsMap = credentialsMap;
|
||||
this.securityGroupMap = securityGroupMap;
|
||||
this.createUniqueKeyPair = createUniqueKeyPair;
|
||||
this.createSecurityGroupIfNeeded = createSecurityGroupIfNeeded;
|
||||
this.optionsProvider = optionsProvider;
|
||||
}
|
||||
|
||||
|
@ -123,40 +119,32 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions {
|
|||
if (options.getOverridingCredentials() != null && options.getOverridingCredentials().credential != null) {
|
||||
KeyPair keyPair = KeyPair.builder().region(region).keyName(keyPairName).keyFingerprint("//TODO")
|
||||
.keyMaterial(options.getOverridingCredentials().credential).build();
|
||||
putKeyPairIntoCredentialMap(keyPair);
|
||||
|
||||
RegionAndName key = new RegionAndName(region, group);
|
||||
knownKeys.put(key, keyPair);
|
||||
credentialsMap.invalidate(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.getRunScript() != null) {
|
||||
RegionAndName regionAndName = new RegionAndName(region, keyPairName);
|
||||
checkState(credentialsMap.containsKey(regionAndName),
|
||||
"no private key configured for: %s; please use options.overrideLoginCredentialWith(rsa_private_text)",
|
||||
regionAndName);
|
||||
String message = String.format("no private key configured for: %s; please use options.overrideLoginCredentialWith(rsa_private_text)",
|
||||
regionAndName);
|
||||
// test to see if this is in cache.
|
||||
try {
|
||||
credentialsMap.getUnchecked(regionAndName);
|
||||
} catch (NullPointerException nex) {
|
||||
throw new IllegalArgumentException(message, nex);
|
||||
} catch (UncheckedExecutionException nex) {
|
||||
throw new IllegalArgumentException(message, nex);
|
||||
}
|
||||
}
|
||||
|
||||
return keyPairName;
|
||||
}
|
||||
|
||||
// base EC2 driver currently does not support key import
|
||||
protected String createOrImportKeyPair(String region, String group, TemplateOptions options) {
|
||||
return createUniqueKeyPairAndPutIntoMap(region, group);
|
||||
}
|
||||
|
||||
protected String createUniqueKeyPairAndPutIntoMap(String region, String group) {
|
||||
RegionAndName regionAndName = new RegionAndName(region, group);
|
||||
KeyPair keyPair = createUniqueKeyPair.apply(regionAndName);
|
||||
putKeyPairIntoCredentialMap(keyPair);
|
||||
return keyPair.getKeyName();
|
||||
}
|
||||
|
||||
protected void putKeyPairIntoCredentialMap(KeyPair keyPair) {
|
||||
// get or create incidental resources
|
||||
// TODO race condition. we were using MapMaker, but it doesn't seem to
|
||||
// refresh properly
|
||||
// when
|
||||
// another thread
|
||||
// deletes a key
|
||||
credentialsMap.put(new RegionAndName(keyPair.getRegion(), keyPair.getKeyName()), keyPair);
|
||||
return credentialsMap.getUnchecked(new RegionAndName(region, group)).getKeyName();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
@ -177,11 +165,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions {
|
|||
regionNameAndIngessRulesForMarkerGroup = new RegionNameAndIngressRules(region, markerGroup,
|
||||
options.getInboundPorts(), true);
|
||||
}
|
||||
|
||||
if (!securityGroupMap.containsKey(regionNameAndIngessRulesForMarkerGroup)) {
|
||||
securityGroupMap.put(regionNameAndIngessRulesForMarkerGroup,
|
||||
createSecurityGroupIfNeeded.apply(regionNameAndIngessRulesForMarkerGroup));
|
||||
}
|
||||
// this will create if not yet exists.
|
||||
securityGroupMap.getUnchecked(regionNameAndIngessRulesForMarkerGroup);
|
||||
}
|
||||
return groups.build();
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ import org.jclouds.logging.Logger;
|
|||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
@ -77,7 +78,7 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
|
|||
@VisibleForTesting
|
||||
final ComputeUtils utils;
|
||||
final InstancePresent instancePresent;
|
||||
final Function<RunningInstance, Credentials> instanceToCredentials;
|
||||
final Cache<RunningInstance, Credentials> instanceToCredentials;
|
||||
final Map<String, Credentials> credentialStore;
|
||||
final Provider<TemplateBuilder> templateBuilderProvider;
|
||||
|
||||
|
@ -87,7 +88,7 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
|
|||
Provider<TemplateBuilder> templateBuilderProvider,
|
||||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
|
||||
InstancePresent instancePresent, Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
|
||||
Function<RunningInstance, Credentials> instanceToCredentials, Map<String, Credentials> credentialStore,
|
||||
Cache<RunningInstance, Credentials> instanceToCredentials, Map<String, Credentials> credentialStore,
|
||||
ComputeUtils utils) {
|
||||
this.client = checkNotNull(client, "client");
|
||||
this.templateBuilderProvider = checkNotNull(templateBuilderProvider, "templateBuilderProvider");
|
||||
|
|
|
@ -18,16 +18,16 @@
|
|||
*/
|
||||
package org.jclouds.ec2.compute.suppliers;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
|
@ -36,16 +36,16 @@ import com.google.common.collect.Sets;
|
|||
*/
|
||||
@Singleton
|
||||
public class EC2ImageSupplier implements Supplier<Set<? extends Image>> {
|
||||
private final Supplier<Map<RegionAndName, ? extends Image>> map;
|
||||
private final Supplier<Cache<RegionAndName, ? extends Image>> map;
|
||||
|
||||
@Inject
|
||||
EC2ImageSupplier(Supplier<Map<RegionAndName, ? extends Image>> map) {
|
||||
EC2ImageSupplier(Supplier<Cache<RegionAndName, ? extends Image>> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<? extends Image> get() {
|
||||
return Sets.newLinkedHashSet(map.get().values());
|
||||
return Sets.newLinkedHashSet(map.get().asMap().values());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ import static org.jclouds.ec2.options.DescribeImagesOptions.Builder.ownedBy;
|
|||
import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_AMI_OWNERS;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
|
@ -45,16 +45,19 @@ import org.jclouds.logging.Logger;
|
|||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableMap.Builder;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class RegionAndNameToImageSupplier implements Supplier<Map<RegionAndName, ? extends Image>> {
|
||||
public class RegionAndNameToImageSupplier implements Supplier<Cache<RegionAndName, ? extends Image>> {
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
@ -63,20 +66,23 @@ public class RegionAndNameToImageSupplier implements Supplier<Map<RegionAndName,
|
|||
private final DescribeImagesParallel describer;
|
||||
private final String[] amiOwners;
|
||||
private final EC2ImageParser parser;
|
||||
private final Map<RegionAndName, Image> images;
|
||||
private final Map<RegionAndName, Image> knownImages;
|
||||
private final CacheLoader<RegionAndName, Image> regionAndIdToImage;
|
||||
|
||||
@Inject
|
||||
protected RegionAndNameToImageSupplier(@Region Set<String> regions, DescribeImagesParallel describer,
|
||||
@Named(PROPERTY_EC2_AMI_OWNERS) String[] amiOwners, EC2ImageParser parser, Map<RegionAndName, Image> images) {
|
||||
@Named(PROPERTY_EC2_AMI_OWNERS) String[] amiOwners, EC2ImageParser parser,
|
||||
Map<RegionAndName, Image> knownImages, CacheLoader<RegionAndName, Image> regionAndIdToImage) {
|
||||
this.regions = regions;
|
||||
this.describer = describer;
|
||||
this.amiOwners = amiOwners;
|
||||
this.parser = parser;
|
||||
this.images = images;
|
||||
this.knownImages = knownImages;
|
||||
this.regionAndIdToImage = regionAndIdToImage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<RegionAndName, ? extends Image> get() {
|
||||
public Cache<RegionAndName, ? extends Image> get() {
|
||||
if (amiOwners.length == 0) {
|
||||
logger.debug(">> no owners specified, skipping image parsing");
|
||||
} else {
|
||||
|
@ -87,8 +93,8 @@ public class RegionAndNameToImageSupplier implements Supplier<Map<RegionAndName,
|
|||
|
||||
Iterable<? extends Image> parsedImages = ImmutableSet.copyOf(filter(transform(describer.apply(queries), parser), Predicates
|
||||
.notNull()));
|
||||
|
||||
images.putAll(uniqueIndex(parsedImages, new Function<Image, RegionAndName>() {
|
||||
knownImages.clear();
|
||||
knownImages.putAll(uniqueIndex(parsedImages, new Function<Image, RegionAndName>() {
|
||||
|
||||
@Override
|
||||
public RegionAndName apply(Image from) {
|
||||
|
@ -96,14 +102,18 @@ public class RegionAndNameToImageSupplier implements Supplier<Map<RegionAndName,
|
|||
}
|
||||
|
||||
}));
|
||||
|
||||
logger.debug("<< images(%d)", images.size());
|
||||
logger.debug("<< images(%d)", knownImages.size());
|
||||
}
|
||||
return images;
|
||||
Cache<RegionAndName, Image> cache = CacheBuilder.newBuilder().build(regionAndIdToImage);
|
||||
// seed the cache
|
||||
for (RegionAndName image : knownImages.keySet()) {
|
||||
cache.getUnchecked(image);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
public Iterable<Entry<String, DescribeImagesOptions>> getDescribeQueriesForOwnersInRegions(Set<String> regions,
|
||||
String[] amiOwners) {
|
||||
String[] amiOwners) {
|
||||
DescribeImagesOptions options = getOptionsForOwners(amiOwners);
|
||||
Builder<String, DescribeImagesOptions> builder = ImmutableMap.<String, DescribeImagesOptions> builder();
|
||||
for (String region : regions)
|
||||
|
|
|
@ -25,8 +25,10 @@ import static org.easymock.classextension.EasyMock.verify;
|
|||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jclouds.ec2.EC2Client;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.ec2.domain.KeyPair;
|
||||
import org.jclouds.ec2.services.KeyPairClient;
|
||||
import org.testng.annotations.Test;
|
||||
|
@ -38,58 +40,127 @@ import com.google.common.base.Supplier;
|
|||
*/
|
||||
@Test(groups = "unit")
|
||||
public class CreateUniqueKeyPairTest {
|
||||
@SuppressWarnings( { "unchecked" })
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@Test
|
||||
public void testApply() throws UnknownHostException {
|
||||
EC2Client client = createMock(EC2Client.class);
|
||||
KeyPairClient keyClient = createMock(KeyPairClient.class);
|
||||
Supplier<String> uniqueIdSupplier = createMock(Supplier.class);
|
||||
Map<RegionAndName, KeyPair> knownKeys = createMock(Map.class);
|
||||
|
||||
KeyPair pair = createMock(KeyPair.class);
|
||||
|
||||
expect(client.getKeyPairServices()).andReturn(keyClient).atLeastOnce();
|
||||
|
||||
expect(uniqueIdSupplier.get()).andReturn("1");
|
||||
expect(keyClient.createKeyPairInRegion("region", "jclouds#tag#region#1")).andReturn(pair);
|
||||
expect(keyClient.createKeyPairInRegion("region", "jclouds#group#region#1")).andReturn(pair);
|
||||
|
||||
replay(client);
|
||||
replay(knownKeys);
|
||||
replay(keyClient);
|
||||
replay(uniqueIdSupplier);
|
||||
|
||||
CreateUniqueKeyPair parser = new CreateUniqueKeyPair(client, uniqueIdSupplier);
|
||||
CreateUniqueKeyPair parser = new CreateUniqueKeyPair(knownKeys, client, uniqueIdSupplier);
|
||||
|
||||
assertEquals(parser.createNewKeyPairInRegion("region", "tag"), pair);
|
||||
assertEquals(parser.createNewKeyPairInRegion("region", "group"), pair);
|
||||
|
||||
verify(client);
|
||||
verify(knownKeys);
|
||||
verify(keyClient);
|
||||
verify(uniqueIdSupplier);
|
||||
}
|
||||
|
||||
@SuppressWarnings( { "unchecked" })
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@Test
|
||||
public void testApplyWithIllegalStateException() throws UnknownHostException {
|
||||
EC2Client client = createMock(EC2Client.class);
|
||||
KeyPairClient keyClient = createMock(KeyPairClient.class);
|
||||
Supplier<String> uniqueIdSupplier = createMock(Supplier.class);
|
||||
Map<RegionAndName, KeyPair> knownKeys = createMock(Map.class);
|
||||
|
||||
KeyPair pair = createMock(KeyPair.class);
|
||||
|
||||
expect(client.getKeyPairServices()).andReturn(keyClient).atLeastOnce();
|
||||
|
||||
expect(uniqueIdSupplier.get()).andReturn("1");
|
||||
expect(keyClient.createKeyPairInRegion("region", "jclouds#tag#region#1")).andThrow(new IllegalStateException());
|
||||
expect(keyClient.createKeyPairInRegion("region", "jclouds#group#region#1")).andThrow(new IllegalStateException());
|
||||
expect(uniqueIdSupplier.get()).andReturn("2");
|
||||
expect(keyClient.createKeyPairInRegion("region", "jclouds#tag#region#2")).andReturn(pair);
|
||||
expect(keyClient.createKeyPairInRegion("region", "jclouds#group#region#2")).andReturn(pair);
|
||||
|
||||
replay(client);
|
||||
replay(knownKeys);
|
||||
replay(keyClient);
|
||||
replay(uniqueIdSupplier);
|
||||
|
||||
CreateUniqueKeyPair parser = new CreateUniqueKeyPair(client, uniqueIdSupplier);
|
||||
CreateUniqueKeyPair parser = new CreateUniqueKeyPair(knownKeys, client, uniqueIdSupplier);
|
||||
|
||||
assertEquals(parser.createNewKeyPairInRegion("region", "tag"), pair);
|
||||
assertEquals(parser.createNewKeyPairInRegion("region", "group"), pair);
|
||||
|
||||
verify(client);
|
||||
verify(knownKeys);
|
||||
verify(keyClient);
|
||||
verify(uniqueIdSupplier);
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@Test
|
||||
public void testApplyWhenKnownKeyExists() throws UnknownHostException {
|
||||
EC2Client client = createMock(EC2Client.class);
|
||||
KeyPairClient keyClient = createMock(KeyPairClient.class);
|
||||
Supplier<String> uniqueIdSupplier = createMock(Supplier.class);
|
||||
Map<RegionAndName, KeyPair> knownKeys = createMock(Map.class);
|
||||
|
||||
KeyPair pair = createMock(KeyPair.class);
|
||||
|
||||
expect(knownKeys.containsKey(new RegionAndName("region", "group"))).andReturn(true);
|
||||
expect(knownKeys.get(new RegionAndName("region", "group"))).andReturn(pair);
|
||||
|
||||
replay(client);
|
||||
replay(knownKeys);
|
||||
replay(keyClient);
|
||||
replay(uniqueIdSupplier);
|
||||
|
||||
CreateUniqueKeyPair parser = new CreateUniqueKeyPair(knownKeys, client, uniqueIdSupplier);
|
||||
|
||||
assertEquals(parser.load(new RegionAndName("region", "group")), pair);
|
||||
|
||||
verify(client);
|
||||
verify(knownKeys);
|
||||
verify(keyClient);
|
||||
verify(uniqueIdSupplier);
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@Test
|
||||
public void testApplyWhenKnownKeyDoesntExist() throws UnknownHostException {
|
||||
EC2Client client = createMock(EC2Client.class);
|
||||
KeyPairClient keyClient = createMock(KeyPairClient.class);
|
||||
Supplier<String> uniqueIdSupplier = createMock(Supplier.class);
|
||||
Map<RegionAndName, KeyPair> knownKeys = createMock(Map.class);
|
||||
|
||||
KeyPair pair = createMock(KeyPair.class);
|
||||
|
||||
expect(client.getKeyPairServices()).andReturn(keyClient).atLeastOnce();
|
||||
|
||||
expect(knownKeys.containsKey(new RegionAndName("region", "group"))).andReturn(false);
|
||||
expect(uniqueIdSupplier.get()).andReturn("1");
|
||||
expect(keyClient.createKeyPairInRegion("region", "jclouds#group#region#1")).andThrow(new IllegalStateException());
|
||||
expect(uniqueIdSupplier.get()).andReturn("2");
|
||||
expect(keyClient.createKeyPairInRegion("region", "jclouds#group#region#2")).andReturn(pair);
|
||||
|
||||
replay(client);
|
||||
replay(knownKeys);
|
||||
replay(keyClient);
|
||||
replay(uniqueIdSupplier);
|
||||
|
||||
CreateUniqueKeyPair parser = new CreateUniqueKeyPair(knownKeys, client, uniqueIdSupplier);
|
||||
|
||||
assertEquals(parser.load(new RegionAndName("region", "group")), pair);
|
||||
|
||||
verify(client);
|
||||
verify(knownKeys);
|
||||
verify(keyClient);
|
||||
verify(uniqueIdSupplier);
|
||||
|
||||
|
|
|
@ -26,13 +26,15 @@ import static org.easymock.classextension.EasyMock.verify;
|
|||
import static org.jclouds.ec2.options.DescribeImagesOptions.Builder.imageIds;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.ec2.EC2Client;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.ec2.services.AMIClient;
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
|
@ -46,46 +48,85 @@ public class RegionAndIdToImageTest {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testApply() {
|
||||
public void testApply() throws ExecutionException {
|
||||
|
||||
EC2ImageParser parser = createMock(EC2ImageParser.class);
|
||||
EC2Client caller = createMock(EC2Client.class);
|
||||
AMIClient client = createMock(AMIClient.class);
|
||||
Map<RegionAndName, Image> knownImages = createMock(Map.class);
|
||||
|
||||
org.jclouds.ec2.domain.Image ec2Image = createMock(org.jclouds.ec2.domain.Image.class);
|
||||
Image image = createNiceMock(Image.class);
|
||||
Set<? extends org.jclouds.ec2.domain.Image> images = ImmutableSet.<org.jclouds.ec2.domain.Image> of(ec2Image);
|
||||
|
||||
expect(knownImages.containsKey(new RegionAndName("region", "ami"))).andReturn(false);
|
||||
expect(caller.getAMIServices()).andReturn(client).atLeastOnce();
|
||||
expect(client.describeImagesInRegion("region", imageIds("ami"))).andReturn(Set.class.cast(images));
|
||||
expect(parser.apply(ec2Image)).andReturn(image);
|
||||
|
||||
replay(knownImages);
|
||||
replay(caller);
|
||||
replay(image);
|
||||
replay(parser);
|
||||
replay(client);
|
||||
|
||||
RegionAndIdToImage function = new RegionAndIdToImage(parser, caller);
|
||||
RegionAndIdToImage function = new RegionAndIdToImage(knownImages, parser, caller);
|
||||
|
||||
assertEquals(function.apply(new RegionAndName("region", "ami")), image);
|
||||
assertEquals(function.load(new RegionAndName("region", "ami")), image);
|
||||
|
||||
verify(caller);
|
||||
verify(image);
|
||||
verify(parser);
|
||||
verify(image);
|
||||
verify(knownImages);
|
||||
verify(client);
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testApplyNotFound() {
|
||||
public void testApplyWhenFoundDoesntCallClient() throws ExecutionException {
|
||||
|
||||
EC2ImageParser parser = createMock(EC2ImageParser.class);
|
||||
EC2Client caller = createMock(EC2Client.class);
|
||||
AMIClient client = createMock(AMIClient.class);
|
||||
Map<RegionAndName, Image> knownImages = createMock(Map.class);
|
||||
|
||||
Image image = createNiceMock(Image.class);
|
||||
|
||||
expect(knownImages.containsKey(new RegionAndName("region", "ami"))).andReturn(true);
|
||||
expect(knownImages.get(new RegionAndName("region", "ami"))).andReturn(image);
|
||||
|
||||
replay(knownImages);
|
||||
replay(caller);
|
||||
replay(image);
|
||||
replay(parser);
|
||||
replay(client);
|
||||
|
||||
RegionAndIdToImage function = new RegionAndIdToImage(knownImages, parser, caller);
|
||||
|
||||
assertEquals(function.load(new RegionAndName("region", "ami")), image);
|
||||
|
||||
verify(caller);
|
||||
verify(image);
|
||||
verify(image);
|
||||
verify(knownImages);
|
||||
verify(client);
|
||||
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test(expectedExceptions = ExecutionException.class)
|
||||
public void testApplyNotFoundMakesExecutionException() throws ExecutionException {
|
||||
|
||||
EC2ImageParser parser = createMock(EC2ImageParser.class);
|
||||
EC2Client caller = createMock(EC2Client.class);
|
||||
AMIClient client = createMock(AMIClient.class);
|
||||
Map<RegionAndName, Image> knownImages = createMock(Map.class);
|
||||
|
||||
org.jclouds.ec2.domain.Image ec2Image = createMock(org.jclouds.ec2.domain.Image.class);
|
||||
Image image = createNiceMock(Image.class);
|
||||
Set<? extends org.jclouds.ec2.domain.Image> images = ImmutableSet.<org.jclouds.ec2.domain.Image> of(ec2Image);
|
||||
|
||||
expect(knownImages.containsKey(new RegionAndName("region", "ami"))).andReturn(false);
|
||||
expect(caller.getAMIServices()).andReturn(client).atLeastOnce();
|
||||
expect(client.describeImagesInRegion("region", imageIds("ami"))).andReturn(Set.class.cast(images));
|
||||
expect(parser.apply(ec2Image)).andThrow(new ResourceNotFoundException());
|
||||
|
@ -93,45 +134,52 @@ public class RegionAndIdToImageTest {
|
|||
replay(caller);
|
||||
replay(image);
|
||||
replay(parser);
|
||||
replay(knownImages);
|
||||
replay(client);
|
||||
|
||||
RegionAndIdToImage function = new RegionAndIdToImage(parser, caller);
|
||||
RegionAndIdToImage function = new RegionAndIdToImage(knownImages, parser, caller);
|
||||
|
||||
assertEquals(function.apply(new RegionAndName("region", "ami")), null);
|
||||
assertEquals(function.load(new RegionAndName("region", "ami")), null);
|
||||
|
||||
verify(caller);
|
||||
verify(image);
|
||||
verify(parser);
|
||||
verify(knownImages);
|
||||
verify(client);
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testApplyNoSuchElementException() {
|
||||
@Test(expectedExceptions = ExecutionException.class)
|
||||
public void testApplyNoSuchElementExceptionMakesExecutionException() throws ExecutionException {
|
||||
|
||||
EC2ImageParser parser = createMock(EC2ImageParser.class);
|
||||
EC2Client caller = createMock(EC2Client.class);
|
||||
AMIClient client = createMock(AMIClient.class);
|
||||
Map<RegionAndName, Image> knownImages = createMock(Map.class);
|
||||
|
||||
org.jclouds.ec2.domain.Image ec2Image = createMock(org.jclouds.ec2.domain.Image.class);
|
||||
Image image = createNiceMock(Image.class);
|
||||
Set<? extends org.jclouds.ec2.domain.Image> images = ImmutableSet.<org.jclouds.ec2.domain.Image> of(ec2Image);
|
||||
|
||||
expect(knownImages.containsKey(new RegionAndName("region", "ami"))).andReturn(false);
|
||||
expect(caller.getAMIServices()).andReturn(client).atLeastOnce();
|
||||
expect(client.describeImagesInRegion("region", imageIds("ami"))).andReturn(Set.class.cast(images));
|
||||
expect(parser.apply(ec2Image)).andThrow(new NoSuchElementException());
|
||||
|
||||
replay(caller);
|
||||
replay(image);
|
||||
replay(knownImages);
|
||||
replay(parser);
|
||||
replay(client);
|
||||
|
||||
RegionAndIdToImage function = new RegionAndIdToImage(parser, caller);
|
||||
RegionAndIdToImage function = new RegionAndIdToImage(knownImages, parser, caller);
|
||||
|
||||
assertEquals(function.apply(new RegionAndName("region", "ami")), null);
|
||||
assertEquals(function.load(new RegionAndName("region", "ami")), null);
|
||||
|
||||
verify(caller);
|
||||
verify(image);
|
||||
verify(knownImages);
|
||||
verify(parser);
|
||||
verify(client);
|
||||
|
||||
|
|
|
@ -25,8 +25,6 @@ import java.net.UnknownHostException;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
|
||||
import org.jclouds.compute.domain.Hardware;
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
|
@ -43,14 +41,18 @@ import org.jclouds.ec2.compute.domain.RegionAndName;
|
|||
import org.jclouds.ec2.domain.InstanceState;
|
||||
import org.jclouds.ec2.domain.RunningInstance;
|
||||
import org.jclouds.ec2.xml.DescribeInstancesResponseHandlerTest;
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
|
@ -167,14 +169,14 @@ public class RunningInstanceToNodeMetadataTest {
|
|||
// Handle the case when the installed AMI no longer can be found in AWS.
|
||||
|
||||
// Create a null-returning function to simulate that the AMI can't be found.
|
||||
Function<RegionAndName, Image> nullReturningFunction = new Function<RegionAndName, Image>() {
|
||||
CacheLoader<RegionAndName, Image> nullReturningFunction = new CacheLoader<RegionAndName, Image>() {
|
||||
|
||||
@Override
|
||||
public Image apply(@Nullable RegionAndName from) {
|
||||
public Image load(@Nullable RegionAndName from) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Map<RegionAndName, Image> instanceToImage = new MapMaker().makeComputingMap(nullReturningFunction);
|
||||
Cache<RegionAndName, Image> instanceToImage = CacheBuilder.newBuilder().build(nullReturningFunction);
|
||||
|
||||
RunningInstanceToNodeMetadata parser = createNodeParser(ImmutableSet.of(m1_small32().build()), ImmutableSet
|
||||
.of(provider), ImmutableMap.<String, Credentials> of(),
|
||||
|
@ -197,25 +199,31 @@ public class RunningInstanceToNodeMetadataTest {
|
|||
}
|
||||
|
||||
protected RunningInstanceToNodeMetadata createNodeParser(final ImmutableSet<Hardware> hardware,
|
||||
final ImmutableSet<Location> locations, Set<org.jclouds.compute.domain.Image> images,
|
||||
final ImmutableSet<Location> locations, final Set<org.jclouds.compute.domain.Image> images,
|
||||
Map<String, Credentials> credentialStore) {
|
||||
Map<InstanceState, NodeState> instanceToNodeState = EC2ComputeServiceDependenciesModule.instanceToNodeState;
|
||||
|
||||
Map<RegionAndName, Image> instanceToImage = Maps.uniqueIndex(images, new Function<Image, RegionAndName>() {
|
||||
CacheLoader<RegionAndName, Image> getRealImage = new CacheLoader<RegionAndName, Image>() {
|
||||
|
||||
@Override
|
||||
public RegionAndName apply(Image from) {
|
||||
return new RegionAndName(from.getLocation().getId(), from.getProviderId());
|
||||
public Image load(@Nullable RegionAndName from) {
|
||||
return Maps.uniqueIndex(images, new Function<Image, RegionAndName>() {
|
||||
|
||||
@Override
|
||||
public RegionAndName apply(Image from) {
|
||||
return new RegionAndName(from.getLocation().getId(), from.getProviderId());
|
||||
}
|
||||
|
||||
}).get(from);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
Cache<RegionAndName, Image> instanceToImage = CacheBuilder.newBuilder().build(getRealImage);
|
||||
return createNodeParser(hardware, locations, credentialStore, instanceToNodeState, instanceToImage);
|
||||
}
|
||||
|
||||
private RunningInstanceToNodeMetadata createNodeParser(final ImmutableSet<Hardware> hardware,
|
||||
final ImmutableSet<Location> locations, Map<String, Credentials> credentialStore,
|
||||
Map<InstanceState, NodeState> instanceToNodeState, Map<RegionAndName, Image> instanceToImage) {
|
||||
Map<InstanceState, NodeState> instanceToNodeState, Cache<RegionAndName, Image> instanceToImage) {
|
||||
Supplier<Set<? extends Location>> locationSupplier = new Supplier<Set<? extends Location>>() {
|
||||
|
||||
@Override
|
||||
|
@ -233,7 +241,8 @@ public class RunningInstanceToNodeMetadataTest {
|
|||
|
||||
};
|
||||
RunningInstanceToNodeMetadata parser = new RunningInstanceToNodeMetadata(instanceToNodeState, credentialStore,
|
||||
instanceToImage, locationSupplier, hardwareSupplier);
|
||||
Suppliers.<Cache<RegionAndName, ? extends Image>> ofInstance(instanceToImage), locationSupplier,
|
||||
hardwareSupplier);
|
||||
return parser;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@ import static org.testng.Assert.assertEquals;
|
|||
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import javax.inject.Provider;
|
||||
|
||||
|
@ -46,11 +45,12 @@ import org.jclouds.ec2.compute.domain.RegionAndName;
|
|||
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
|
@ -67,22 +67,21 @@ public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest {
|
|||
|
||||
@Override
|
||||
protected EC2TemplateBuilderImpl createTemplateBuilder(final Image knownImage,
|
||||
@Memoized Supplier<Set<? extends Location>> locations, @Memoized Supplier<Set<? extends Image>> images,
|
||||
@Memoized Supplier<Set<? extends Hardware>> sizes, Location defaultLocation,
|
||||
Provider<TemplateOptions> optionsProvider, Provider<TemplateBuilder> templateBuilderProvider) {
|
||||
@Memoized Supplier<Set<? extends Location>> locations, @Memoized Supplier<Set<? extends Image>> images,
|
||||
@Memoized Supplier<Set<? extends Hardware>> sizes, Location defaultLocation,
|
||||
Provider<TemplateOptions> optionsProvider, Provider<TemplateBuilder> templateBuilderProvider) {
|
||||
final RegionAndName knownRegionAndName = new RegionAndName("region", "ami");
|
||||
|
||||
ConcurrentMap<RegionAndName, Image> imageMap = new MapMaker()
|
||||
.makeComputingMap(new Function<RegionAndName, Image>() {
|
||||
@Override
|
||||
public Image apply(RegionAndName from) {
|
||||
return from.equals(knownRegionAndName) ? knownImage : null;
|
||||
}
|
||||
Cache<RegionAndName, ? extends Image> imageMap = CacheBuilder.newBuilder().build(new CacheLoader<RegionAndName, Image>() {
|
||||
@Override
|
||||
public Image load(RegionAndName from) {
|
||||
return from.equals(knownRegionAndName) ? knownImage : null;
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
return new EC2TemplateBuilderImpl(locations, images, sizes, Suppliers.ofInstance(defaultLocation),
|
||||
optionsProvider, templateBuilderProvider, imageMap);
|
||||
optionsProvider, templateBuilderProvider, Suppliers.<Cache<RegionAndName, ? extends Image>>ofInstance(imageMap));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -91,11 +90,11 @@ public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest {
|
|||
Location location = new LocationBuilder().scope(LocationScope.REGION).id("region").description("region").build();
|
||||
|
||||
Supplier<Set<? extends Location>> locations = Suppliers.<Set<? extends Location>> ofInstance(ImmutableSet
|
||||
.<Location> of(location));
|
||||
.<Location> of(location));
|
||||
Supplier<Set<? extends Image>> images = Suppliers.<Set<? extends Image>> ofInstance(Sets
|
||||
.<Image> newLinkedHashSet());
|
||||
.<Image> newLinkedHashSet());
|
||||
Supplier<Set<? extends Hardware>> sizes = Suppliers.<Set<? extends Hardware>> ofInstance(ImmutableSet
|
||||
.<Hardware> of(c1_medium().build()));
|
||||
.<Hardware> of(c1_medium().build()));
|
||||
|
||||
Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
|
||||
Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
|
||||
|
@ -127,7 +126,7 @@ public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest {
|
|||
replay(templateBuilderProvider);
|
||||
|
||||
TemplateBuilderImpl template = createTemplateBuilder(knownImage, locations, images, sizes, location,
|
||||
optionsProvider, templateBuilderProvider);
|
||||
optionsProvider, templateBuilderProvider);
|
||||
|
||||
assertEquals(template.imageId("region/ami").build().getImage(), knownImage);
|
||||
|
||||
|
@ -144,10 +143,10 @@ public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest {
|
|||
Location location = new LocationBuilder().scope(LocationScope.REGION).id("region").description("region").build();
|
||||
|
||||
Supplier<Set<? extends Location>> locations = Suppliers.<Set<? extends Location>> ofInstance(ImmutableSet
|
||||
.<Location> of(location));
|
||||
.<Location> of(location));
|
||||
Supplier<Set<? extends Image>> images = Suppliers.<Set<? extends Image>> ofInstance(ImmutableSet.<Image> of());
|
||||
Supplier<Set<? extends Hardware>> sizes = Suppliers.<Set<? extends Hardware>> ofInstance(ImmutableSet
|
||||
.<Hardware> of(c1_medium().build()));
|
||||
.<Hardware> of(c1_medium().build()));
|
||||
|
||||
Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
|
||||
Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
|
||||
|
@ -162,7 +161,7 @@ public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest {
|
|||
replay(templateBuilderProvider);
|
||||
|
||||
TemplateBuilderImpl template = createTemplateBuilder(knownImage, locations, images, sizes, location,
|
||||
optionsProvider, templateBuilderProvider);
|
||||
optionsProvider, templateBuilderProvider);
|
||||
try {
|
||||
template.imageId("ami").build();
|
||||
assert false;
|
||||
|
@ -181,10 +180,10 @@ public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest {
|
|||
Location location = new LocationBuilder().scope(LocationScope.REGION).id("region").description("region").build();
|
||||
|
||||
Supplier<Set<? extends Location>> locations = Suppliers.<Set<? extends Location>> ofInstance(ImmutableSet
|
||||
.<Location> of(location));
|
||||
.<Location> of(location));
|
||||
Supplier<Set<? extends Image>> images = Suppliers.<Set<? extends Image>> ofInstance(ImmutableSet.<Image> of());
|
||||
Supplier<Set<? extends Hardware>> sizes = Suppliers.<Set<? extends Hardware>> ofInstance(ImmutableSet
|
||||
.<Hardware> of(c1_medium().build()));
|
||||
.<Hardware> of(c1_medium().build()));
|
||||
|
||||
Location defaultLocation = createMock(Location.class);
|
||||
Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
|
||||
|
@ -202,7 +201,7 @@ public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest {
|
|||
replay(templateBuilderProvider);
|
||||
|
||||
TemplateBuilderImpl template = createTemplateBuilder(knownImage, locations, images, sizes, defaultLocation,
|
||||
optionsProvider, templateBuilderProvider);
|
||||
optionsProvider, templateBuilderProvider);
|
||||
|
||||
assertEquals(template.imageId("region/bad").build().getImage(), knownImage);
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import static org.testng.Assert.assertEquals;
|
|||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.inject.Provider;
|
||||
|
||||
|
@ -38,8 +39,6 @@ import org.jclouds.domain.Credentials;
|
|||
import org.jclouds.ec2.compute.domain.EC2HardwareBuilder;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.ec2.compute.domain.RegionNameAndIngressRules;
|
||||
import org.jclouds.ec2.compute.functions.CreateSecurityGroupIfNeeded;
|
||||
import org.jclouds.ec2.compute.functions.CreateUniqueKeyPair;
|
||||
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
|
||||
import org.jclouds.ec2.domain.BlockDeviceMapping;
|
||||
import org.jclouds.ec2.domain.KeyPair;
|
||||
|
@ -48,14 +47,14 @@ import org.jclouds.encryption.internal.Base64;
|
|||
import org.jclouds.scriptbuilder.domain.Statements;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit")
|
||||
@Test(groups = "unit", singleThreaded = true, testName = "CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest")
|
||||
public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
||||
|
||||
private static final Provider<RunInstancesOptions> OPTIONS_PROVIDER = new javax.inject.Provider<RunInstancesOptions>() {
|
||||
|
@ -209,7 +208,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
verifyStrategy(strategy);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_reusesKeyWhenToldToWithRunScriptButNoCredentials() {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
|
@ -225,7 +224,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
|
||||
expect(options.getOverridingCredentials()).andReturn(null);
|
||||
expect(options.getRunScript()).andReturn(Statements.exec("echo foo"));
|
||||
expect(strategy.credentialsMap.containsKey(new RegionAndName(region, userSuppliedKeyPair))).andReturn(false);
|
||||
|
||||
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, userSuppliedKeyPair))).andThrow(new NullPointerException());
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
|
@ -256,7 +256,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
|
||||
expect(options.getOverridingCredentials()).andReturn(null);
|
||||
expect(options.getRunScript()).andReturn(Statements.exec("echo foo"));
|
||||
expect(strategy.credentialsMap.containsKey(new RegionAndName(region, userSuppliedKeyPair))).andReturn(true);
|
||||
|
||||
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, userSuppliedKeyPair))).andReturn(keyPair);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
|
@ -287,11 +288,13 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
|
||||
expect(options.getOverridingCredentials()).andReturn(new Credentials(null, "MyRsa")).atLeastOnce();
|
||||
expect(
|
||||
strategy.credentialsMap.put(new RegionAndName(region, userSuppliedKeyPair), KeyPair.builder()
|
||||
.region(region).keyName(userSuppliedKeyPair).keyFingerprint("//TODO").keyMaterial("MyRsa").build()))
|
||||
.andReturn(null);
|
||||
strategy.knownKeys.put(
|
||||
new RegionAndName(region, tag),
|
||||
KeyPair.builder().region(region).keyName(userSuppliedKeyPair).keyFingerprint("//TODO")
|
||||
.keyMaterial("MyRsa").build())).andReturn(null);
|
||||
strategy.credentialsMap.invalidate(new RegionAndName(region, tag));
|
||||
expect(options.getRunScript()).andReturn(Statements.exec("echo foo"));
|
||||
expect(strategy.credentialsMap.containsKey(new RegionAndName(region, userSuppliedKeyPair))).andReturn(true);
|
||||
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, userSuppliedKeyPair))).andReturn(keyPair);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
|
@ -307,7 +310,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
verifyStrategy(strategy);
|
||||
}
|
||||
|
||||
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_createsNewKeyPairAndReturnsItsNameByDefault() {
|
||||
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_createsNewKeyPairAndReturnsItsNameByDefault()
|
||||
throws ExecutionException {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
|
@ -323,11 +327,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
// setup expectations
|
||||
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
|
||||
expect(options.shouldAutomaticallyCreateKeyPair()).andReturn(shouldAutomaticallyCreateKeyPair);
|
||||
expect(strategy.createUniqueKeyPair.apply(new RegionAndName(region, tag))).andReturn(keyPair);
|
||||
expect(keyPair.getRegion()).andReturn(region).atLeastOnce();
|
||||
expect(keyPair.getKeyName()).andReturn(systemGeneratedKeyPairName).atLeastOnce();
|
||||
expect(strategy.credentialsMap.put(new RegionAndName(region, systemGeneratedKeyPairName), keyPair)).andReturn(
|
||||
null);
|
||||
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, tag))).andReturn(keyPair);
|
||||
expect(options.getRunScript()).andReturn(null);
|
||||
|
||||
// replay mocks
|
||||
|
@ -377,7 +378,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
verifyStrategy(strategy);
|
||||
}
|
||||
|
||||
public void testGetSecurityGroupsForTagAndOptions_createsNewGroupByDefaultWhenNoPortsAreSpecifiedWhenDoesntExist() {
|
||||
public void testGetSecurityGroupsForTagAndOptions_createsNewGroupByDefaultWhenNoPortsAreSpecifiedWhenDoesntExist()
|
||||
throws ExecutionException {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
|
@ -385,7 +387,6 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
Set<String> groupIds = ImmutableSet.<String> of();
|
||||
int[] ports = new int[] {};
|
||||
boolean shouldAuthorizeSelf = true;
|
||||
boolean groupExisted = false;
|
||||
Set<String> returnVal = ImmutableSet.<String> of(generatedMarkerGroup);
|
||||
|
||||
// create mocks
|
||||
|
@ -397,9 +398,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
expect(options.getInboundPorts()).andReturn(ports).atLeastOnce();
|
||||
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
|
||||
ports, shouldAuthorizeSelf);
|
||||
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(groupExisted);
|
||||
expect(strategy.createSecurityGroupIfNeeded.apply(regionNameAndIngressRules)).andReturn(generatedMarkerGroup);
|
||||
expect(strategy.securityGroupMap.put(regionNameAndIngressRules, generatedMarkerGroup)).andReturn(null);
|
||||
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(tag);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
|
@ -413,7 +412,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
verifyStrategy(strategy);
|
||||
}
|
||||
|
||||
public void testGetSecurityGroupsForTagAndOptions_createsNewGroupByDefaultWhenPortsAreSpecifiedWhenDoesntExist() {
|
||||
public void testGetSecurityGroupsForTagAndOptions_createsNewGroupByDefaultWhenPortsAreSpecifiedWhenDoesntExist()
|
||||
throws ExecutionException {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
|
@ -421,7 +421,6 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
Set<String> groupIds = ImmutableSet.<String> of();
|
||||
int[] ports = new int[] { 22, 80 };
|
||||
boolean shouldAuthorizeSelf = true;
|
||||
boolean groupExisted = false;
|
||||
Set<String> returnVal = ImmutableSet.<String> of(generatedMarkerGroup);
|
||||
|
||||
// create mocks
|
||||
|
@ -433,9 +432,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
expect(options.getInboundPorts()).andReturn(ports).atLeastOnce();
|
||||
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
|
||||
ports, shouldAuthorizeSelf);
|
||||
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(groupExisted);
|
||||
expect(strategy.createSecurityGroupIfNeeded.apply(regionNameAndIngressRules)).andReturn(generatedMarkerGroup);
|
||||
expect(strategy.securityGroupMap.put(regionNameAndIngressRules, generatedMarkerGroup)).andReturn(null);
|
||||
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(generatedMarkerGroup);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
|
@ -449,7 +446,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
verifyStrategy(strategy);
|
||||
}
|
||||
|
||||
public void testGetSecurityGroupsForTagAndOptions_reusesGroupByDefaultWhenNoPortsAreSpecifiedWhenDoesExist() {
|
||||
public void testGetSecurityGroupsForTagAndOptions_reusesGroupByDefaultWhenNoPortsAreSpecifiedWhenDoesExist()
|
||||
throws ExecutionException {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
|
@ -457,7 +455,6 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
Set<String> groupIds = ImmutableSet.<String> of();
|
||||
int[] ports = new int[] {};
|
||||
boolean shouldAuthorizeSelf = true;
|
||||
boolean groupExisted = true;
|
||||
Set<String> returnVal = ImmutableSet.<String> of(generatedMarkerGroup);
|
||||
|
||||
// create mocks
|
||||
|
@ -469,7 +466,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
expect(options.getInboundPorts()).andReturn(ports).atLeastOnce();
|
||||
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
|
||||
ports, shouldAuthorizeSelf);
|
||||
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(groupExisted);
|
||||
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(generatedMarkerGroup);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
|
@ -501,13 +498,9 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
// setup expectations
|
||||
expect(options.getGroups()).andReturn(groupIds).atLeastOnce();
|
||||
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
|
||||
ports, shouldAuthorizeSelf); // note
|
||||
// this
|
||||
// works
|
||||
// since
|
||||
// there's
|
||||
// no equals on portsq
|
||||
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(groupExisted);
|
||||
ports, shouldAuthorizeSelf);
|
||||
|
||||
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(groupExisted ? "tag" : null);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
|
@ -522,28 +515,24 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
}
|
||||
|
||||
private void verifyStrategy(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions strategy) {
|
||||
verify(strategy.knownKeys);
|
||||
verify(strategy.credentialsMap);
|
||||
verify(strategy.securityGroupMap);
|
||||
verify(strategy.createUniqueKeyPair);
|
||||
verify(strategy.createSecurityGroupIfNeeded);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions setupStrategy() {
|
||||
Map<RegionAndName, KeyPair> credentialsMap = createMock(Map.class);
|
||||
Map<RegionAndName, String> securityGroupMap = createMock(Map.class);
|
||||
CreateUniqueKeyPair createUniqueKeyPair = createMock(CreateUniqueKeyPair.class);
|
||||
Function<RegionNameAndIngressRules, String> createSecurityGroupIfNeeded = createMock(CreateSecurityGroupIfNeeded.class);
|
||||
|
||||
return new CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions(credentialsMap, securityGroupMap,
|
||||
createUniqueKeyPair, createSecurityGroupIfNeeded, OPTIONS_PROVIDER);
|
||||
Map<RegionAndName, KeyPair> knownKeys = createMock(Map.class);
|
||||
Cache<RegionAndName, KeyPair> credentialsMap = createMock(Cache.class);
|
||||
Cache<RegionAndName, String> securityGroupMap = createMock(Cache.class);
|
||||
return new CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions(knownKeys, credentialsMap, securityGroupMap,
|
||||
OPTIONS_PROVIDER);
|
||||
}
|
||||
|
||||
private void replayStrategy(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions strategy) {
|
||||
replay(strategy.knownKeys);
|
||||
replay(strategy.credentialsMap);
|
||||
replay(strategy.securityGroupMap);
|
||||
replay(strategy.createUniqueKeyPair);
|
||||
replay(strategy.createSecurityGroupIfNeeded);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ import org.jclouds.ec2.options.RunInstancesOptions;
|
|||
import org.jclouds.ec2.services.InstanceClient;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
@ -222,7 +222,7 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
|
|||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = createMock(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.class);
|
||||
InstancePresent instancePresent = createMock(InstancePresent.class);
|
||||
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata = createMock(RunningInstanceToNodeMetadata.class);
|
||||
Function<RunningInstance, Credentials> instanceToCredentials = createMock(Function.class);
|
||||
Cache<RunningInstance, Credentials> instanceToCredentials = createMock(Cache.class);
|
||||
Map<String, Credentials> credentialStore = createMock(Map.class);
|
||||
ComputeUtils utils = createMock(ComputeUtils.class);
|
||||
return new EC2CreateNodesInGroupThenAddToSet(client, Providers.<TemplateBuilder> of(template),
|
||||
|
|
|
@ -25,13 +25,17 @@ import java.net.URI;
|
|||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.aws.domain.Region;
|
||||
import org.jclouds.aws.filters.FormSigner;
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.date.DateService;
|
||||
import org.jclouds.ec2.EC2AsyncClient;
|
||||
import org.jclouds.ec2.EC2Client;
|
||||
import org.jclouds.ec2.EC2ContextBuilder;
|
||||
import org.jclouds.ec2.EC2PropertiesBuilder;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.ec2.config.EC2RestClientModule;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.RequiresHttp;
|
||||
|
@ -42,8 +46,12 @@ import org.jclouds.rest.RestContextSpec;
|
|||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.Provides;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
|
@ -58,6 +66,19 @@ public abstract class BaseEC2AsyncClientTest<T> extends RestClientTest<T> {
|
|||
super(EC2Client.class, EC2AsyncClient.class, DELEGATE_MAP);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
Cache<RegionAndName, Image> provide(){
|
||||
return CacheBuilder.newBuilder().build(new CacheLoader<RegionAndName, Image>() {
|
||||
|
||||
@Override
|
||||
public Image load(RegionAndName key) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String provideTimeStamp(DateService dateService, int expiration) {
|
||||
return "2009-11-08T15:54:08.897Z";
|
||||
|
|
|
@ -46,7 +46,6 @@ import org.jclouds.compute.domain.internal.VolumeImpl;
|
|||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.elasticstack.ElasticStackAsyncClient;
|
||||
import org.jclouds.elasticstack.ElasticStackClient;
|
||||
import org.jclouds.elasticstack.domain.Device;
|
||||
import org.jclouds.elasticstack.domain.Drive;
|
||||
|
@ -62,23 +61,25 @@ import org.jclouds.logging.Logger;
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSet.Builder;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
|
||||
/**
|
||||
* defines the connection between the {@link ElasticStackClient} implementation and the jclouds
|
||||
* {@link ComputeService}
|
||||
* defines the connection between the {@link ElasticStackClient} implementation
|
||||
* and the jclouds {@link ComputeService}
|
||||
*
|
||||
*/
|
||||
@Singleton
|
||||
public class ElasticStackComputeServiceAdapter implements
|
||||
ComputeServiceAdapter<ServerInfo, Hardware, DriveInfo, Location> {
|
||||
ComputeServiceAdapter<ServerInfo, Hardware, DriveInfo, Location> {
|
||||
private final ElasticStackClient client;
|
||||
private final ElasticStackAsyncClient aclient;
|
||||
private final Predicate<DriveInfo> driveNotClaimed;
|
||||
private final Map<String, WellKnownImage> preinstalledImages;
|
||||
private final Map<String, DriveInfo> cache;
|
||||
private final Cache<String, DriveInfo> cache;
|
||||
private final JustProvider locationSupplier;
|
||||
private final String defaultVncPassword;
|
||||
private final ExecutorService executor;
|
||||
|
@ -88,13 +89,11 @@ public class ElasticStackComputeServiceAdapter implements
|
|||
protected Logger logger = Logger.NULL;
|
||||
|
||||
@Inject
|
||||
public ElasticStackComputeServiceAdapter(ElasticStackClient client, ElasticStackAsyncClient aclient,
|
||||
Predicate<DriveInfo> driveNotClaimed, JustProvider locationSupplier,
|
||||
Map<String, WellKnownImage> preinstalledImages, Map<String, DriveInfo> cache,
|
||||
@Named(ElasticStackConstants.PROPERTY_VNC_PASSWORD) String defaultVncPassword,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
||||
public ElasticStackComputeServiceAdapter(ElasticStackClient client, Predicate<DriveInfo> driveNotClaimed,
|
||||
JustProvider locationSupplier, Map<String, WellKnownImage> preinstalledImages, Cache<String, DriveInfo> cache,
|
||||
@Named(ElasticStackConstants.PROPERTY_VNC_PASSWORD) String defaultVncPassword,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
||||
this.client = checkNotNull(client, "client");
|
||||
this.aclient = checkNotNull(aclient, "aclient");
|
||||
this.driveNotClaimed = checkNotNull(driveNotClaimed, "driveNotClaimed");
|
||||
this.locationSupplier = checkNotNull(locationSupplier, "locationSupplier");
|
||||
this.preinstalledImages = checkNotNull(preinstalledImages, "preinstalledImages");
|
||||
|
@ -105,12 +104,12 @@ public class ElasticStackComputeServiceAdapter implements
|
|||
|
||||
@Override
|
||||
public ServerInfo createNodeWithGroupEncodedIntoNameThenStoreCredentials(String tag, String name, Template template,
|
||||
Map<String, Credentials> credentialStore) {
|
||||
Map<String, Credentials> credentialStore) {
|
||||
long bootSize = (long) (template.getHardware().getVolumes().get(0).getSize() * 1024 * 1024 * 1024l);
|
||||
|
||||
logger.debug(">> creating boot drive bytes(%d)", bootSize);
|
||||
DriveInfo drive = client.createDrive(new Drive.Builder().name(template.getImage().getId()).size(bootSize)
|
||||
.build());
|
||||
DriveInfo drive = client
|
||||
.createDrive(new Drive.Builder().name(template.getImage().getId()).size(bootSize).build());
|
||||
logger.debug("<< drive(%s)", drive.getUuid());
|
||||
|
||||
logger.debug(">> imaging boot drive source(%s)", template.getImage().getId());
|
||||
|
@ -121,17 +120,16 @@ public class ElasticStackComputeServiceAdapter implements
|
|||
client.destroyDrive(drive.getUuid());
|
||||
throw new IllegalStateException("could not image drive in time!");
|
||||
}
|
||||
cache.put(drive.getUuid(), drive);
|
||||
|
||||
Server toCreate = small(name, drive.getUuid(), defaultVncPassword).mem(template.getHardware().getRam()).cpu(
|
||||
(int) (template.getHardware().getProcessors().get(0).getSpeed())).build();
|
||||
Server toCreate = small(name, drive.getUuid(), defaultVncPassword).mem(template.getHardware().getRam())
|
||||
.cpu((int) (template.getHardware().getProcessors().get(0).getSpeed())).build();
|
||||
|
||||
ServerInfo from = client.createServer(toCreate);
|
||||
client.startServer(from.getUuid());
|
||||
from = client.getServerInfo(from.getUuid());
|
||||
// store the credentials so that later functions can use them
|
||||
credentialStore.put("node#"+ from.getUuid(), new Credentials(template.getImage().getDefaultCredentials().identity,
|
||||
from.getVnc().getPassword()));
|
||||
credentialStore.put("node#" + from.getUuid(), new Credentials(
|
||||
template.getImage().getDefaultCredentials().identity, from.getVnc().getPassword()));
|
||||
return from;
|
||||
}
|
||||
|
||||
|
@ -155,30 +153,40 @@ public class ElasticStackComputeServiceAdapter implements
|
|||
return "sizeLessThanOrEqual(" + size + ")";
|
||||
}
|
||||
|
||||
}).ids(id).ram(ram).processors(ImmutableList.of(new Processor(1, cpu))).volumes(
|
||||
ImmutableList.<Volume> of(new VolumeImpl(size, true, true))).build());
|
||||
}).ids(id).ram(ram).processors(ImmutableList.of(new Processor(1, cpu)))
|
||||
.volumes(ImmutableList.<Volume> of(new VolumeImpl(size, true, true))).build());
|
||||
}
|
||||
return hardware.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* look up the current standard images and do not error out, if they are not found.
|
||||
* look up the current standard images and do not error out, if they are not
|
||||
* found.
|
||||
*/
|
||||
@Override
|
||||
public Iterable<DriveInfo> listImages() {
|
||||
Iterable<DriveInfo> drives = transformParallel(preinstalledImages.keySet(),
|
||||
new Function<String, Future<DriveInfo>>() {
|
||||
new Function<String, Future<DriveInfo>>() {
|
||||
|
||||
@Override
|
||||
public Future<DriveInfo> apply(String input) {
|
||||
return aclient.getDriveInfo(input);
|
||||
@Override
|
||||
public Future<DriveInfo> apply(String input) {
|
||||
try {
|
||||
return Futures.immediateFuture(cache.getUnchecked(input));
|
||||
} catch (NullPointerException e) {
|
||||
logger.debug("drive %s not found", input);
|
||||
} catch (UncheckedExecutionException e) {
|
||||
logger.warn(e, "error finding drive %s: %s", input, e.getMessage());
|
||||
}
|
||||
return Futures.immediateFuture(null);
|
||||
}
|
||||
|
||||
}, executor, null, logger, "drives");
|
||||
Iterable<DriveInfo> returnVal = filter(drives, notNull());
|
||||
for (DriveInfo drive : returnVal)
|
||||
cache.put(drive.getUuid(), drive);
|
||||
return returnVal;
|
||||
@Override
|
||||
public String toString() {
|
||||
return "seedDriveCache()";
|
||||
}
|
||||
|
||||
}, executor, null, logger, "drives");
|
||||
return filter(drives, notNull());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -38,10 +38,10 @@ import org.jclouds.elasticstack.ElasticStackAsyncClient;
|
|||
import org.jclouds.elasticstack.ElasticStackClient;
|
||||
import org.jclouds.elasticstack.compute.ElasticStackComputeServiceAdapter;
|
||||
import org.jclouds.elasticstack.compute.functions.ServerInfoToNodeMetadata;
|
||||
import org.jclouds.elasticstack.compute.functions.WellKnownImageToImage;
|
||||
import org.jclouds.elasticstack.compute.functions.ServerInfoToNodeMetadata.DeviceToVolume;
|
||||
import org.jclouds.elasticstack.compute.functions.ServerInfoToNodeMetadata.FindImageForId;
|
||||
import org.jclouds.elasticstack.compute.functions.ServerInfoToNodeMetadata.GetImageIdFromServer;
|
||||
import org.jclouds.elasticstack.compute.functions.WellKnownImageToImage;
|
||||
import org.jclouds.elasticstack.domain.Device;
|
||||
import org.jclouds.elasticstack.domain.DriveInfo;
|
||||
import org.jclouds.elasticstack.domain.Server;
|
||||
|
@ -59,7 +59,9 @@ import com.google.common.base.Function;
|
|||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
@ -104,12 +106,12 @@ public class ElasticStackComputeServiceContextModule
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected Map<String, DriveInfo> cache(GetDrive getDrive) {
|
||||
return new MapMaker().makeComputingMap(getDrive);
|
||||
protected Cache<String, DriveInfo> cache(GetDrive getDrive) {
|
||||
return CacheBuilder.newBuilder().build(getDrive);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static class GetDrive implements Function<String, DriveInfo> {
|
||||
public static class GetDrive extends CacheLoader<String, DriveInfo> {
|
||||
private final ElasticStackClient client;
|
||||
|
||||
@Inject
|
||||
|
@ -118,7 +120,7 @@ public class ElasticStackComputeServiceContextModule
|
|||
}
|
||||
|
||||
@Override
|
||||
public DriveInfo apply(String input) {
|
||||
public DriveInfo load(String input) {
|
||||
return client.getDriveInfo(input);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,27 +18,44 @@
|
|||
*/
|
||||
package org.jclouds.elasticstack.compute.functions;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import org.jclouds.collect.FindResourceInSet;
|
||||
import org.jclouds.collect.Memoized;
|
||||
import org.jclouds.compute.domain.*;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.elasticstack.domain.*;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.jclouds.compute.util.ComputeServiceUtils.parseGroupFromName;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.jclouds.compute.util.ComputeServiceUtils.parseGroupFromName;
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.collect.FindResourceInSet;
|
||||
import org.jclouds.collect.Memoized;
|
||||
import org.jclouds.compute.domain.HardwareBuilder;
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.compute.domain.NodeMetadataBuilder;
|
||||
import org.jclouds.compute.domain.NodeState;
|
||||
import org.jclouds.compute.domain.Processor;
|
||||
import org.jclouds.compute.domain.Volume;
|
||||
import org.jclouds.compute.domain.VolumeBuilder;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.elasticstack.domain.Device;
|
||||
import org.jclouds.elasticstack.domain.DriveInfo;
|
||||
import org.jclouds.elasticstack.domain.Server;
|
||||
import org.jclouds.elasticstack.domain.ServerInfo;
|
||||
import org.jclouds.elasticstack.domain.ServerStatus;
|
||||
import org.jclouds.logging.Logger;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
|
@ -93,16 +110,19 @@ public class ServerInfoToNodeMetadata implements Function<ServerInfo, NodeMetada
|
|||
builder.state(serverStatusToNodeState.get(from.getStatus()));
|
||||
builder.publicAddresses(ImmutableSet.<String> of(from.getNics().get(0).getDhcp()));
|
||||
builder.privateAddresses(ImmutableSet.<String> of());
|
||||
builder.credentials(credentialStore.get("node#"+ from.getUuid()));
|
||||
builder.credentials(credentialStore.get("node#" + from.getUuid()));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static final class DeviceToVolume implements Function<Device, Volume> {
|
||||
private final Map<String, DriveInfo> cache;
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private final Cache<String, DriveInfo> cache;
|
||||
|
||||
@Inject
|
||||
public DeviceToVolume(Map<String, DriveInfo> cache) {
|
||||
public DeviceToVolume(Cache<String, DriveInfo> cache) {
|
||||
this.cache = checkNotNull(cache, "cache");
|
||||
}
|
||||
|
||||
|
@ -110,27 +130,34 @@ public class ServerInfoToNodeMetadata implements Function<ServerInfo, NodeMetada
|
|||
public Volume apply(Device input) {
|
||||
VolumeBuilder builder = new VolumeBuilder();
|
||||
builder.id(input.getId());
|
||||
DriveInfo drive = cache.get(input.getDriveUuid());
|
||||
if (drive != null) {
|
||||
try {
|
||||
DriveInfo drive = cache.getUnchecked(input.getDriveUuid());
|
||||
builder.size(drive.getSize() / 1024 / 1024f);
|
||||
} catch (NullPointerException e) {
|
||||
logger.debug("drive %s not found", input.getDriveUuid());
|
||||
} catch (UncheckedExecutionException e) {
|
||||
logger.warn(e, "error finding drive %s: %s", input.getDriveUuid(), e.getMessage());
|
||||
}
|
||||
return new VolumeBuilder().durable(true).type(Volume.Type.NAS).build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When we create the boot drive of the server, by convention we set the name to the image it
|
||||
* came from.
|
||||
* When we create the boot drive of the server, by convention we set the name
|
||||
* to the image it came from.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
@Singleton
|
||||
public static class GetImageIdFromServer implements Function<Server, String> {
|
||||
private final Map<String, DriveInfo> cache;
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private final Cache<String, DriveInfo> cache;
|
||||
|
||||
@Inject
|
||||
public GetImageIdFromServer(Map<String, DriveInfo> cache) {
|
||||
public GetImageIdFromServer(Cache<String, DriveInfo> cache) {
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
|
@ -141,9 +168,12 @@ public class ServerInfoToNodeMetadata implements Function<ServerInfo, NodeMetada
|
|||
Device bootDevice = from.getDevices().get(bootDeviceId);
|
||||
if (bootDevice != null) {
|
||||
try {
|
||||
imageId = cache.get(bootDevice.getDriveUuid()).getName();
|
||||
DriveInfo drive = cache.getUnchecked(bootDevice.getDriveUuid());
|
||||
imageId = drive.getName();
|
||||
} catch (NullPointerException e) {
|
||||
|
||||
logger.debug("drive %s not found", bootDevice.getDriveUuid());
|
||||
} catch (UncheckedExecutionException e) {
|
||||
logger.warn(e, "error finding drive %s: %s", bootDevice.getDriveUuid(), e.getMessage());
|
||||
}
|
||||
}
|
||||
return imageId;
|
||||
|
|
|
@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
import static org.jclouds.trmk.vcloud_0_8.reference.TerremarkConstants.PROPERTY_TERREMARK_EXTENSION_NS;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
@ -33,6 +34,7 @@ import org.jclouds.rest.binders.BindToStringPayload;
|
|||
import org.jclouds.util.Patterns;
|
||||
import org.jclouds.util.Strings2;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/**
|
||||
|
@ -61,9 +63,13 @@ public class BindAddInternetServiceToXmlPayload implements MapBinder {
|
|||
String description = postParams.get("description");
|
||||
String payload = Strings2.replaceTokens(xmlTemplate,
|
||||
ImmutableMap.of("name", name, "protocol", protocol, "port", port, "enabled", enabled, "ns", ns));
|
||||
payload = Strings2.replaceAll(payload, Patterns.TOKEN_TO_PATTERN.get("description"), description == null ? ""
|
||||
: String.format("\n\t<Description>%s</Description>", description));
|
||||
payload = Strings2.replaceAll(payload, Patterns.TOKEN_TO_PATTERN.get("monitor"), getMonitorString(postParams));
|
||||
try {
|
||||
payload = Strings2.replaceAll(payload, Patterns.TOKEN_TO_PATTERN.get("description"), description == null ? ""
|
||||
: String.format("\n\t<Description>%s</Description>", description));
|
||||
payload = Strings2.replaceAll(payload, Patterns.TOKEN_TO_PATTERN.get("monitor"), getMonitorString(postParams));
|
||||
} catch (ExecutionException e) {
|
||||
Throwables.propagate(e);
|
||||
}
|
||||
return stringBinder.bindToRequest(request, payload);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
import static org.jclouds.trmk.vcloud_0_8.reference.TerremarkConstants.PROPERTY_TERREMARK_EXTENSION_NS;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
@ -33,6 +34,7 @@ import org.jclouds.rest.binders.BindToStringPayload;
|
|||
import org.jclouds.util.Patterns;
|
||||
import org.jclouds.util.Strings2;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/**
|
||||
|
@ -62,8 +64,12 @@ public class BindAddNodeServiceToXmlPayload implements MapBinder {
|
|||
|
||||
String payload = Strings2.replaceTokens(xmlTemplate,
|
||||
ImmutableMap.of("name", name, "ipAddress", ipAddress, "port", port, "enabled", enabled, "ns", ns));
|
||||
payload = Strings2.replaceAll(payload, Patterns.TOKEN_TO_PATTERN.get("description"), description == null ? ""
|
||||
: String.format("\n <Description>%s</Description>", description));
|
||||
try {
|
||||
payload = Strings2.replaceAll(payload, Patterns.TOKEN_TO_PATTERN.get("description"), description == null ? ""
|
||||
: String.format("\n <Description>%s</Description>", description));
|
||||
} catch (ExecutionException e) {
|
||||
Throwables.propagate(e);
|
||||
}
|
||||
return stringBinder.bindToRequest(request, payload);
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ public interface ComputeServiceConstants {
|
|||
public static class ReferenceData {
|
||||
@Inject(optional = true)
|
||||
@Named(PROPERTY_OS_VERSION_MAP_JSON)
|
||||
public String osVersionMapJson = "{\"suse\":{\"\":\"\",\"11\":\"11\",\"11 SP1\":\"11 SP1\"},\"debian\":{\"\":\"\",\"lenny\":\"5.0\",\"squeeze\":\"6.0\"},\"centos\":{\"\":\"\",\"5\":\"5.0\",\"5.2\":\"5.2\",\"5.3\":\"5.3\",\"5.4\":\"5.4\",\"5.5\":\"5.5\"},\"rhel\":{\"\":\"\",\"5\":\"5.0\",\"5.2\":\"5.2\",\"5.3\":\"5.3\",\"5.4\":\"5.4\",\"5.5\":\"5.5\"},\"solaris\":{\"\":\"\",\"10\":\"10\"},\"ubuntu\":{\"\":\"\",\"hardy\":\"8.04\",\"karmic\":\"9.10\",\"lucid\":\"10.04\",\"10.04.1\":\"10.04\",\"maverick\":\"10.10\",\"natty\":\"11.04\",\"oneiric\":\"11.10\"},\"windows\":{\"\":\"\",\"2003\":\"2003\",\"2003 Standard\":\"2003\",\"2003 R2\":\"2003 R2\",\"2008\":\"2008\",\"2008 Web\":\"2008\",\"2008 Server\":\"2008\",\"Server 2008\":\"2008\",\"2008 R1\":\"2008 R1\",\"2008 R2\":\"2008 R2\",\"Server 2008 R2\":\"2008 R2\",\"2008 Server R2\":\"2008 R2\",\"2008 SP2\":\"2008 SP2\",\"Server 2008 SP2\":\"2008 SP2\"}}";
|
||||
public String osVersionMapJson = "{\"suse\":{\"\":\"\",\"11\":\"11\",\"11 SP1\":\"11 SP1\"},\"debian\":{\"\":\"\",\"lenny\":\"5.0\",\"squeeze\":\"6.0\"},\"centos\":{\"\":\"\",\"5\":\"5.0\",\"5.2\":\"5.2\",\"5.3\":\"5.3\",\"5.4\":\"5.4\",\"5.5\":\"5.5\",\"5.6\":\"5.6\",\"5.7\":\"5.7\",\"6.0\":\"6.0\"},\"rhel\":{\"\":\"\",\"5\":\"5.0\",\"5.2\":\"5.2\",\"5.3\":\"5.3\",\"5.4\":\"5.4\",\"5.5\":\"5.5\",\"5.6\":\"5.6\",\"5.7\":\"5.7\",\"6.0\":\"6.0\"},\"solaris\":{\"\":\"\",\"10\":\"10\"},\"ubuntu\":{\"\":\"\",\"hardy\":\"8.04\",\"karmic\":\"9.10\",\"lucid\":\"10.04\",\"10.04.1\":\"10.04\",\"maverick\":\"10.10\",\"natty\":\"11.04\",\"oneiric\":\"11.10\"},\"windows\":{\"\":\"\",\"2003\":\"2003\",\"2003 Standard\":\"2003\",\"2003 R2\":\"2003 R2\",\"2008\":\"2008\",\"2008 Web\":\"2008\",\"2008 Server\":\"2008\",\"Server 2008\":\"2008\",\"2008 R1\":\"2008 R1\",\"2008 R2\":\"2008 R2\",\"Server 2008 R2\":\"2008 R2\",\"2008 Server R2\":\"2008 R2\",\"2008 SP2\":\"2008 SP2\",\"Server 2008 SP2\":\"2008 SP2\"}}";
|
||||
}
|
||||
|
||||
@Singleton
|
||||
|
|
|
@ -109,7 +109,7 @@
|
|||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>r09</version>
|
||||
<version>10.0-rc2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ public class Futures {
|
|||
// ExecutionException / CancellationException / RuntimeException
|
||||
// The task is done, run the listeners.
|
||||
}
|
||||
executionList.run();
|
||||
executionList.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -116,7 +116,7 @@ public class Futures {
|
|||
if (delegate.isDone()) {
|
||||
// If the delegate is already done, run the execution list
|
||||
// immediately on the current thread.
|
||||
executionList.run();
|
||||
executionList.execute();
|
||||
return;
|
||||
}
|
||||
adapterExecutor.execute(new CallGetAndRunExecutionList<T>(delegate, executionList));
|
||||
|
|
|
@ -26,7 +26,6 @@ import java.lang.reflect.Proxy;
|
|||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -38,6 +37,7 @@ import org.jclouds.internal.ClassMethodArgs;
|
|||
import org.jclouds.rest.annotations.Delegate;
|
||||
import org.jclouds.util.Throwables2;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
@ -62,13 +62,13 @@ public class SyncProxy implements InvocationHandler {
|
|||
private final Map<Method, Method> methodMap;
|
||||
private final Map<Method, Method> syncMethodMap;
|
||||
private final Map<Method, Long> timeoutMap;
|
||||
private final ConcurrentMap<ClassMethodArgs, Object> delegateMap;
|
||||
private final Cache<ClassMethodArgs, Object> delegateMap;
|
||||
private final Map<Class<?>, Class<?>> sync2Async;
|
||||
private static final Set<Method> objectMethods = ImmutableSet.of(Object.class.getMethods());
|
||||
|
||||
@Inject
|
||||
public SyncProxy(Class<?> declaring, Object async,
|
||||
@Named("sync") ConcurrentMap<ClassMethodArgs, Object> delegateMap, Map<Class<?>, Class<?>> sync2Async)
|
||||
@Named("sync") Cache<ClassMethodArgs, Object> delegateMap, Map<Class<?>, Class<?>> sync2Async)
|
||||
throws SecurityException, NoSuchMethodException {
|
||||
this.delegateMap = delegateMap;
|
||||
this.delegate = async;
|
||||
|
|
|
@ -20,10 +20,11 @@ package org.jclouds.json.internal;
|
|||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
|
@ -46,29 +47,26 @@ public class EnumTypeAdapterThatReturnsFromValue<T extends Enum<T>> implements J
|
|||
try {
|
||||
return (T) Enum.valueOf((Class<T>) classOfT, json.getAsString());
|
||||
} catch (IllegalArgumentException e) {
|
||||
Method converter = classToConvert.get(classOfT);
|
||||
if (converter != null)
|
||||
try {
|
||||
return (T) converter.invoke(null, json.getAsString());
|
||||
} catch (Exception e1) {
|
||||
throw e;
|
||||
}
|
||||
else
|
||||
try {
|
||||
Method converter = classToConvert.get((Class<?>) classOfT);
|
||||
return (T) converter.invoke(null, json.getAsString());
|
||||
} catch (Exception e1) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final static Map<Class<?>, Method> classToConvert = new MapMaker()
|
||||
.makeComputingMap(new Function<Class<?>, Method>() {
|
||||
private final static Cache<Class<?>, Method> classToConvert = CacheBuilder.newBuilder()
|
||||
.build(new CacheLoader<Class<?>, Method>() {
|
||||
|
||||
@Override
|
||||
public Method apply(Class<?> from) {
|
||||
public Method load(Class<?> from) throws ExecutionException {
|
||||
try {
|
||||
Method method = from.getMethod("fromValue", String.class);
|
||||
method.setAccessible(true);
|
||||
return method;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
throw new ExecutionException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ package org.jclouds.rest.binders;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.net.InternetDomainName.fromLenient;
|
||||
import static com.google.common.net.InternetDomainName.isValidLenient;
|
||||
import static com.google.common.net.InternetDomainName.from;
|
||||
import static com.google.common.net.InternetDomainName.isValid;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
|
@ -51,9 +51,9 @@ public class BindAsHostPrefix implements Binder {
|
|||
@SuppressWarnings("unchecked")
|
||||
public <R extends HttpRequest> R bindToRequest(R request, Object payload) {
|
||||
checkNotNull(payload, "hostprefix");
|
||||
checkArgument(isValidLenient(request.getEndpoint().getHost()), "this is only valid for hostnames: " + request);
|
||||
checkArgument(isValid(request.getEndpoint().getHost()), "this is only valid for hostnames: " + request);
|
||||
UriBuilder builder = uriBuilderProvider.get().uri(request.getEndpoint());
|
||||
InternetDomainName name = fromLenient(request.getEndpoint().getHost()).child(payload.toString());
|
||||
InternetDomainName name = from(request.getEndpoint().getHost()).child(payload.toString());
|
||||
builder.host(name.name());
|
||||
return (R) request.toBuilder().endpoint(builder.build()).build();
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
package org.jclouds.rest.config;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
@ -28,6 +27,7 @@ import org.jclouds.concurrent.internal.SyncProxy;
|
|||
import org.jclouds.internal.ClassMethodArgs;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Key;
|
||||
import com.google.inject.Provider;
|
||||
|
@ -58,8 +58,8 @@ public class ClientProvider<S, A> implements Provider<S> {
|
|||
@Singleton
|
||||
public S get() {
|
||||
A client = (A) injector.getInstance(Key.get(asyncClientType));
|
||||
ConcurrentMap<ClassMethodArgs, Object> delegateMap = injector.getInstance(Key.get(
|
||||
new TypeLiteral<ConcurrentMap<ClassMethodArgs, Object>>() {
|
||||
Cache<ClassMethodArgs, Object> delegateMap = injector.getInstance(Key.get(
|
||||
new TypeLiteral<Cache<ClassMethodArgs, Object>>() {
|
||||
}, Names.named("sync")));
|
||||
try {
|
||||
return (S) SyncProxy.proxy(syncClientType, new SyncProxy(syncClientType, client,
|
||||
|
|
|
@ -21,35 +21,37 @@ package org.jclouds.rest.config;
|
|||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
|
||||
import org.jclouds.concurrent.internal.SyncProxy;
|
||||
import org.jclouds.internal.ClassMethodArgs;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class CreateClientForCaller implements Function<ClassMethodArgs, Object> {
|
||||
private final ConcurrentMap<ClassMethodArgs, Object> asyncMap;
|
||||
private final Provider<ConcurrentMap<ClassMethodArgs, Object>> delegateMap;
|
||||
public class CreateClientForCaller extends CacheLoader<ClassMethodArgs, Object> {
|
||||
private final Cache<ClassMethodArgs, Object> asyncMap;
|
||||
private final Provider<Cache<ClassMethodArgs, Object>> delegateMap;
|
||||
Map<Class<?>, Class<?>> sync2Async;
|
||||
|
||||
@Inject
|
||||
CreateClientForCaller(@Named("async") ConcurrentMap<ClassMethodArgs, Object> asyncMap,
|
||||
@Named("sync") Provider<ConcurrentMap<ClassMethodArgs, Object>> delegateMap) {
|
||||
CreateClientForCaller(@Named("async") Cache<ClassMethodArgs, Object> asyncMap,
|
||||
@Named("sync") Provider<Cache<ClassMethodArgs, Object>> delegateMap) {
|
||||
this.asyncMap = asyncMap;
|
||||
this.delegateMap = delegateMap;
|
||||
}
|
||||
|
||||
public Object apply(ClassMethodArgs from) {
|
||||
@Override
|
||||
public Object load(ClassMethodArgs from) throws ExecutionException {
|
||||
Class<?> syncClass = from.getMethod().getReturnType();
|
||||
Class<?> asyncClass = sync2Async.get(syncClass);
|
||||
checkState(asyncClass != null, "configuration error, sync class " + syncClass
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
package org.jclouds.rest.config;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
@ -30,8 +29,9 @@ import org.jclouds.rest.ConfiguresRestClient;
|
|||
import org.jclouds.rest.RestContext;
|
||||
import org.jclouds.rest.internal.RestContextImpl;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.Scopes;
|
||||
|
@ -125,10 +125,10 @@ public class RestClientModule<S, A> extends AbstractModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
@Named("sync")
|
||||
ConcurrentMap<ClassMethodArgs, Object> provideSyncDelegateMap(
|
||||
Cache<ClassMethodArgs, Object> provideSyncDelegateMap(
|
||||
CreateClientForCaller createClientForCaller) {
|
||||
createClientForCaller.sync2Async = delegates;
|
||||
return new MapMaker().makeComputingMap(createClientForCaller);
|
||||
return CacheBuilder.newBuilder().build(createClientForCaller);
|
||||
}
|
||||
|
||||
}
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.rest.config;
|
||||
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
|
@ -42,8 +40,10 @@ import org.jclouds.rest.internal.RestAnnotationProcessor;
|
|||
import org.jclouds.rest.internal.SeedAnnotationCache;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
|
@ -77,18 +77,18 @@ public class RestModule extends AbstractModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected ConcurrentMap<Class<?>, Boolean> seedAnnotationCache(SeedAnnotationCache seedAnnotationCache) {
|
||||
return new MapMaker().makeComputingMap(seedAnnotationCache);
|
||||
protected Cache<Class<?>, Boolean> seedAnnotationCache(SeedAnnotationCache seedAnnotationCache) {
|
||||
return CacheBuilder.newBuilder().build(seedAnnotationCache);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("async")
|
||||
ConcurrentMap<ClassMethodArgs, Object> provideAsyncDelegateMap(CreateAsyncClientForCaller createAsyncClientForCaller) {
|
||||
return new MapMaker().makeComputingMap(createAsyncClientForCaller);
|
||||
Cache<ClassMethodArgs, Object> provideAsyncDelegateMap(CreateAsyncClientForCaller createAsyncClientForCaller) {
|
||||
return CacheBuilder.newBuilder().build(createAsyncClientForCaller);
|
||||
}
|
||||
|
||||
static class CreateAsyncClientForCaller implements Function<ClassMethodArgs, Object> {
|
||||
static class CreateAsyncClientForCaller extends CacheLoader<ClassMethodArgs, Object> {
|
||||
private final Injector injector;
|
||||
private final AsyncRestClientProxy.Factory factory;
|
||||
|
||||
|
@ -100,7 +100,7 @@ public class RestModule extends AbstractModule {
|
|||
|
||||
@SuppressWarnings( { "unchecked", "rawtypes" })
|
||||
@Override
|
||||
public Object apply(final ClassMethodArgs from) {
|
||||
public Object load(final ClassMethodArgs from) {
|
||||
Class clazz = from.getAsyncClass();
|
||||
TypeLiteral typeLiteral = TypeLiteral.get(clazz);
|
||||
RestAnnotationProcessor util = (RestAnnotationProcessor) injector.getInstance(Key.get(TypeLiteral.get(Types
|
||||
|
@ -108,8 +108,8 @@ public class RestModule extends AbstractModule {
|
|||
// cannot use child injectors due to the super coarse guice lock on
|
||||
// Singleton
|
||||
util.setCaller(from);
|
||||
ConcurrentMap<ClassMethodArgs, Object> delegateMap = injector.getInstance(Key.get(
|
||||
new TypeLiteral<ConcurrentMap<ClassMethodArgs, Object>>() {
|
||||
Cache<ClassMethodArgs, Object> delegateMap = injector.getInstance(Key.get(
|
||||
new TypeLiteral<Cache<ClassMethodArgs, Object>>() {
|
||||
}, Names.named("async")));
|
||||
AsyncRestClientProxy proxy = new AsyncRestClientProxy(injector, factory, util, typeLiteral, delegateMap);
|
||||
injector.injectMembers(proxy);
|
||||
|
|
|
@ -27,7 +27,6 @@ import java.lang.annotation.Annotation;
|
|||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
@ -49,6 +48,7 @@ import org.jclouds.util.Throwables2;
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
|
@ -76,12 +76,12 @@ public class AsyncRestClientProxy<T> implements InvocationHandler {
|
|||
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
private final ConcurrentMap<ClassMethodArgs, Object> delegateMap;
|
||||
private final Cache<ClassMethodArgs, Object> delegateMap;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Inject
|
||||
public AsyncRestClientProxy(Injector injector, Factory factory, RestAnnotationProcessor<T> util,
|
||||
TypeLiteral<T> typeLiteral, @Named("async") ConcurrentMap<ClassMethodArgs, Object> delegateMap) {
|
||||
TypeLiteral<T> typeLiteral, @Named("async") Cache<ClassMethodArgs, Object> delegateMap) {
|
||||
this.injector = injector;
|
||||
this.annotationProcessor = util;
|
||||
this.declaring = (Class<T>) typeLiteral.getRawType();
|
||||
|
|
|
@ -49,9 +49,8 @@ import java.util.Map;
|
|||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
|
@ -98,6 +97,7 @@ import org.jclouds.io.Payloads;
|
|||
import org.jclouds.io.payloads.MultipartForm;
|
||||
import org.jclouds.io.payloads.Part;
|
||||
import org.jclouds.io.payloads.Part.PartOptions;
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
import org.jclouds.json.internal.GsonWrapper;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.rest.Binder;
|
||||
|
@ -137,6 +137,10 @@ import com.google.common.base.Function;
|
|||
import com.google.common.base.Functions;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
@ -145,7 +149,6 @@ import com.google.common.collect.Iterables;
|
|||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.LinkedListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.inject.Inject;
|
||||
|
@ -167,25 +170,25 @@ public class RestAnnotationProcessor<T> {
|
|||
private final Class<T> declaring;
|
||||
|
||||
// TODO replace with Table object
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToBinderParamAnnotation = createMethodToIndexOfParamToAnnotation(BinderParam.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToWrapWithAnnotation = createMethodToIndexOfParamToAnnotation(WrapWith.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToHeaderParamAnnotations = createMethodToIndexOfParamToAnnotation(HeaderParam.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointAnnotations = createMethodToIndexOfParamToAnnotation(Endpoint.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointParamAnnotations = createMethodToIndexOfParamToAnnotation(EndpointParam.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToMatrixParamAnnotations = createMethodToIndexOfParamToAnnotation(MatrixParam.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToFormParamAnnotations = createMethodToIndexOfParamToAnnotation(FormParam.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToQueryParamAnnotations = createMethodToIndexOfParamToAnnotation(QueryParam.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPathParamAnnotations = createMethodToIndexOfParamToAnnotation(PathParam.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPostParamAnnotations = createMethodToIndexOfParamToAnnotation(PayloadParam.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPartParamAnnotations = createMethodToIndexOfParamToAnnotation(PartParam.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToParamParserAnnotations = createMethodToIndexOfParamToAnnotation(ParamParser.class);
|
||||
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToBinderParamAnnotation = createMethodToIndexOfParamToAnnotation(BinderParam.class);
|
||||
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToWrapWithAnnotation = createMethodToIndexOfParamToAnnotation(WrapWith.class);
|
||||
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToHeaderParamAnnotations = createMethodToIndexOfParamToAnnotation(HeaderParam.class);
|
||||
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointAnnotations = createMethodToIndexOfParamToAnnotation(Endpoint.class);
|
||||
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointParamAnnotations = createMethodToIndexOfParamToAnnotation(EndpointParam.class);
|
||||
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToMatrixParamAnnotations = createMethodToIndexOfParamToAnnotation(MatrixParam.class);
|
||||
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToFormParamAnnotations = createMethodToIndexOfParamToAnnotation(FormParam.class);
|
||||
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToQueryParamAnnotations = createMethodToIndexOfParamToAnnotation(QueryParam.class);
|
||||
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToPathParamAnnotations = createMethodToIndexOfParamToAnnotation(PathParam.class);
|
||||
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToPostParamAnnotations = createMethodToIndexOfParamToAnnotation(PayloadParam.class);
|
||||
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToPartParamAnnotations = createMethodToIndexOfParamToAnnotation(PartParam.class);
|
||||
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToParamParserAnnotations = createMethodToIndexOfParamToAnnotation(ParamParser.class);
|
||||
static final Map<MethodKey, Method> delegationMap = newHashMap();
|
||||
|
||||
static Map<Method, Map<Integer, Set<Annotation>>> createMethodToIndexOfParamToAnnotation(
|
||||
static Cache<Method, Cache<Integer, Set<Annotation>>> createMethodToIndexOfParamToAnnotation(
|
||||
final Class<? extends Annotation> annotation) {
|
||||
return new MapMaker().makeComputingMap(new Function<Method, Map<Integer, Set<Annotation>>>() {
|
||||
public Map<Integer, Set<Annotation>> apply(Method method) {
|
||||
return new MapMaker().makeComputingMap(new GetAnnotationsForMethodParameterIndex(method, annotation));
|
||||
return CacheBuilder.newBuilder().build(new CacheLoader<Method, Cache<Integer, Set<Annotation>>>() {
|
||||
public Cache<Integer, Set<Annotation>> load(Method method) {
|
||||
return CacheBuilder.newBuilder().build(CacheLoader.from(new GetAnnotationsForMethodParameterIndex(method, annotation)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -201,17 +204,17 @@ public class RestAnnotationProcessor<T> {
|
|||
|
||||
public Set<Annotation> apply(final Integer index) {
|
||||
return ImmutableSet.<Annotation> copyOf(filter(ImmutableList.copyOf(method.getParameterAnnotations()[index]),
|
||||
new Predicate<Annotation>() {
|
||||
public boolean apply(Annotation input) {
|
||||
return input.annotationType().equals(clazz);
|
||||
}
|
||||
}));
|
||||
new Predicate<Annotation>() {
|
||||
public boolean apply(Annotation input) {
|
||||
return input.annotationType().equals(clazz);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final Class<? extends HttpRequestOptions[]> optionsVarArgsClass = new HttpRequestOptions[] {}
|
||||
.getClass();
|
||||
.getClass();
|
||||
|
||||
private static final Function<? super Entry<String, String>, ? extends Part> ENTRY_TO_PART = new Function<Entry<String, String>, Part>() {
|
||||
|
||||
|
@ -222,23 +225,24 @@ public class RestAnnotationProcessor<T> {
|
|||
|
||||
};
|
||||
|
||||
static final Map<Method, Set<Integer>> methodToIndexesOfOptions = new MapMaker()
|
||||
.makeComputingMap(new Function<Method, Set<Integer>>() {
|
||||
public Set<Integer> apply(Method method) {
|
||||
Builder<Integer> toReturn = ImmutableSet.<Integer> builder();
|
||||
for (int index = 0; index < method.getParameterTypes().length; index++) {
|
||||
Class<?> type = method.getParameterTypes()[index];
|
||||
if (HttpRequestOptions.class.isAssignableFrom(type) || optionsVarArgsClass.isAssignableFrom(type))
|
||||
toReturn.add(index);
|
||||
}
|
||||
return toReturn.build();
|
||||
static final Cache<Method, Set<Integer>> methodToIndexesOfOptions = CacheBuilder.newBuilder().build(
|
||||
new CacheLoader<Method, Set<Integer>>() {
|
||||
@Override
|
||||
public Set<Integer> load(Method method) {
|
||||
Builder<Integer> toReturn = ImmutableSet.<Integer> builder();
|
||||
for (int index = 0; index < method.getParameterTypes().length; index++) {
|
||||
Class<?> type = method.getParameterTypes()[index];
|
||||
if (HttpRequestOptions.class.isAssignableFrom(type) || optionsVarArgsClass.isAssignableFrom(type))
|
||||
toReturn.add(index);
|
||||
}
|
||||
});
|
||||
return toReturn.build();
|
||||
}
|
||||
});
|
||||
|
||||
private final ParseSax.Factory parserFactory;
|
||||
private final HttpUtils utils;
|
||||
private final Provider<UriBuilder> uriBuilderProvider;
|
||||
private final ConcurrentMap<Class<?>, Boolean> seedAnnotationCache;
|
||||
private final Cache<Class<?>, Boolean> seedAnnotationCache;
|
||||
private final String apiVersion;
|
||||
private char[] skips;
|
||||
|
||||
|
@ -252,7 +256,7 @@ public class RestAnnotationProcessor<T> {
|
|||
|
||||
@VisibleForTesting
|
||||
public static Function<HttpResponse, ?> createResponseParser(ParseSax.Factory parserFactory, Injector injector,
|
||||
Method method, HttpRequest request) {
|
||||
Method method, HttpRequest request) {
|
||||
Function<HttpResponse, ?> transformer;
|
||||
Class<? extends HandlerWithResult<?>> handler = getSaxResponseParserClassOrNull(method);
|
||||
if (handler != null) {
|
||||
|
@ -272,9 +276,9 @@ public class RestAnnotationProcessor<T> {
|
|||
if (method.isAnnotationPresent(SelectJson.class)) {
|
||||
Type returnVal = getReturnTypeForMethod(method);
|
||||
if (method.isAnnotationPresent(OnlyElement.class))
|
||||
returnVal = Types.newParameterizedType(Set.class,returnVal);
|
||||
transformer = new ParseFirstJsonValueNamed(injector.getInstance(GsonWrapper.class), TypeLiteral.get(returnVal),
|
||||
method.getAnnotation(SelectJson.class).value());
|
||||
returnVal = Types.newParameterizedType(Set.class, returnVal);
|
||||
transformer = new ParseFirstJsonValueNamed(injector.getInstance(GsonWrapper.class),
|
||||
TypeLiteral.get(returnVal), method.getAnnotation(SelectJson.class).value());
|
||||
if (method.isAnnotationPresent(OnlyElement.class))
|
||||
transformer = Functions.compose(new OnlyElementOrNull(), transformer);
|
||||
} else {
|
||||
|
@ -290,7 +294,7 @@ public class RestAnnotationProcessor<T> {
|
|||
|
||||
@VisibleForTesting
|
||||
public static Function<Exception, ?> createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(
|
||||
Injector injector, Method method) {
|
||||
Injector injector, Method method) {
|
||||
ExceptionParser annotation = method.getAnnotation(ExceptionParser.class);
|
||||
if (annotation != null) {
|
||||
return injector.getInstance(annotation.value());
|
||||
|
@ -300,9 +304,9 @@ public class RestAnnotationProcessor<T> {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Inject
|
||||
public RestAnnotationProcessor(Injector injector, ConcurrentMap<Class<?>, Boolean> seedAnnotationCache,
|
||||
@Named(Constants.PROPERTY_API_VERSION) String apiVersion, ParseSax.Factory parserFactory, HttpUtils utils,
|
||||
TypeLiteral<T> typeLiteral) {
|
||||
public RestAnnotationProcessor(Injector injector, Cache<Class<?>, Boolean> seedAnnotationCache,
|
||||
@Named(Constants.PROPERTY_API_VERSION) String apiVersion, ParseSax.Factory parserFactory, HttpUtils utils,
|
||||
TypeLiteral<T> typeLiteral) throws ExecutionException {
|
||||
this.declaring = (Class<T>) typeLiteral.getRawType();
|
||||
this.injector = injector;
|
||||
this.parserFactory = parserFactory;
|
||||
|
@ -366,8 +370,8 @@ public class RestAnnotationProcessor<T> {
|
|||
this.name = method.getName();
|
||||
this.declaringPackage = method.getDeclaringClass().getPackage();
|
||||
int parametersTypeHashCode = 0;
|
||||
for (Class<?> param: method.getParameterTypes())
|
||||
parametersTypeHashCode +=param.hashCode();
|
||||
for (Class<?> param : method.getParameterTypes())
|
||||
parametersTypeHashCode += param.hashCode();
|
||||
this.parametersTypeHashCode = parametersTypeHashCode;
|
||||
}
|
||||
|
||||
|
@ -379,154 +383,166 @@ public class RestAnnotationProcessor<T> {
|
|||
private URI callerEndpoint;
|
||||
|
||||
public void setCaller(ClassMethodArgs caller) {
|
||||
seedAnnotationCache.get(caller.getMethod().getDeclaringClass());
|
||||
try {
|
||||
seedAnnotationCache.get(caller.getMethod().getDeclaringClass());
|
||||
} catch (ExecutionException e) {
|
||||
Throwables.propagate(e);
|
||||
}
|
||||
this.caller = caller;
|
||||
try {
|
||||
callerEndpoint = getEndpointFor(caller.getMethod(), caller.getArgs(), injector);
|
||||
} catch (IllegalStateException e) {
|
||||
} catch (ExecutionException e) {
|
||||
Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
public GeneratedHttpRequest<T> createRequest(Method method, Object... args) {
|
||||
inputParamValidator.validateMethodParametersOrThrow(method, args);
|
||||
ClassMethodArgs cma = logger.isTraceEnabled() ? new ClassMethodArgs(method.getDeclaringClass(), method, args)
|
||||
try {
|
||||
inputParamValidator.validateMethodParametersOrThrow(method, args);
|
||||
ClassMethodArgs cma = logger.isTraceEnabled() ? new ClassMethodArgs(method.getDeclaringClass(), method, args)
|
||||
: null;
|
||||
|
||||
URI endpoint = callerEndpoint;
|
||||
try {
|
||||
if (endpoint == null) {
|
||||
endpoint = getEndpointFor(method, args, injector);
|
||||
logger.trace("using endpoint %s for %s", endpoint, cma);
|
||||
URI endpoint = callerEndpoint;
|
||||
try {
|
||||
if (endpoint == null) {
|
||||
endpoint = getEndpointFor(method, args, injector);
|
||||
logger.trace("using endpoint %s for %s", endpoint, cma);
|
||||
} else {
|
||||
logger.trace("using endpoint %s from caller %s for %s", caller, endpoint, cma);
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
logger.trace("looking up default endpoint for %s", cma);
|
||||
endpoint = injector.getInstance(Key.get(URI.class, org.jclouds.location.Provider.class));
|
||||
logger.trace("using default endpoint %s for %s", endpoint, cma);
|
||||
}
|
||||
GeneratedHttpRequest.Builder<T> requestBuilder;
|
||||
HttpRequest r = RestAnnotationProcessor.findHttpRequestInArgs(args);
|
||||
if (r != null) {
|
||||
requestBuilder = GeneratedHttpRequest.Builder.<T> from(r);
|
||||
endpoint = r.getEndpoint();
|
||||
} else {
|
||||
logger.trace("using endpoint %s from caller %s for %s", caller, endpoint, cma);
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
logger.trace("looking up default endpoint for %s", cma);
|
||||
endpoint = injector.getInstance(Key.get(URI.class, org.jclouds.location.Provider.class));
|
||||
logger.trace("using default endpoint %s for %s", endpoint, cma);
|
||||
}
|
||||
GeneratedHttpRequest.Builder<T> requestBuilder;
|
||||
HttpRequest r = RestAnnotationProcessor.findHttpRequestInArgs(args);
|
||||
if (r != null) {
|
||||
requestBuilder = GeneratedHttpRequest.Builder.<T> from(r);
|
||||
endpoint = r.getEndpoint();
|
||||
} else {
|
||||
requestBuilder = GeneratedHttpRequest.<T> builder();
|
||||
requestBuilder.method(getHttpMethodOrConstantOrThrowException(method));
|
||||
}
|
||||
|
||||
requestBuilder.declaring(declaring).javaMethod(method).args(args).skips(skips);
|
||||
requestBuilder.filters(getFiltersIfAnnotated(method));
|
||||
|
||||
UriBuilder builder = uriBuilderProvider.get().uri(endpoint);
|
||||
|
||||
Multimap<String, String> tokenValues = LinkedHashMultimap.create();
|
||||
|
||||
tokenValues.put(Constants.PROPERTY_API_VERSION, apiVersion);
|
||||
|
||||
tokenValues.putAll(addPathAndGetTokens(declaring, method, args, builder));
|
||||
|
||||
Multimap<String, String> formParams = addFormParams(tokenValues.entries(), method, args);
|
||||
Multimap<String, String> queryParams = addQueryParams(tokenValues.entries(), method, args);
|
||||
Multimap<String, String> matrixParams = addMatrixParams(tokenValues.entries(), method, args);
|
||||
Multimap<String, String> headers = buildHeaders(tokenValues.entries(), method, args);
|
||||
if (r != null)
|
||||
headers.putAll(r.getHeaders());
|
||||
|
||||
if (shouldAddHostHeader(method)) {
|
||||
StringBuilder hostHeader = new StringBuilder(endpoint.getHost());
|
||||
if (endpoint.getPort() != -1)
|
||||
hostHeader.append(":").append(endpoint.getPort());
|
||||
headers.put(HOST, hostHeader.toString());
|
||||
}
|
||||
|
||||
Payload payload = null;
|
||||
HttpRequestOptions options = findOptionsIn(method, args);
|
||||
if (options != null) {
|
||||
injector.injectMembers(options);// TODO test case
|
||||
for (Entry<String, String> header : options.buildRequestHeaders().entries()) {
|
||||
headers.put(header.getKey(), Strings2.replaceTokens(header.getValue(), tokenValues.entries()));
|
||||
}
|
||||
for (Entry<String, String> matrix : options.buildMatrixParameters().entries()) {
|
||||
matrixParams.put(matrix.getKey(), Strings2.replaceTokens(matrix.getValue(), tokenValues.entries()));
|
||||
}
|
||||
for (Entry<String, String> query : options.buildQueryParameters().entries()) {
|
||||
queryParams.put(query.getKey(), Strings2.replaceTokens(query.getValue(), tokenValues.entries()));
|
||||
}
|
||||
for (Entry<String, String> form : options.buildFormParameters().entries()) {
|
||||
formParams.put(form.getKey(), Strings2.replaceTokens(form.getValue(), tokenValues.entries()));
|
||||
requestBuilder = GeneratedHttpRequest.<T> builder();
|
||||
requestBuilder.method(getHttpMethodOrConstantOrThrowException(method));
|
||||
}
|
||||
|
||||
String pathSuffix = options.buildPathSuffix();
|
||||
if (pathSuffix != null) {
|
||||
builder.path(pathSuffix);
|
||||
requestBuilder.declaring(declaring).javaMethod(method).args(args).skips(skips);
|
||||
requestBuilder.filters(getFiltersIfAnnotated(method));
|
||||
|
||||
UriBuilder builder = uriBuilderProvider.get().uri(endpoint);
|
||||
|
||||
Multimap<String, String> tokenValues = LinkedHashMultimap.create();
|
||||
|
||||
tokenValues.put(Constants.PROPERTY_API_VERSION, apiVersion);
|
||||
|
||||
tokenValues.putAll(addPathAndGetTokens(declaring, method, args, builder));
|
||||
|
||||
Multimap<String, String> formParams = addFormParams(tokenValues.entries(), method, args);
|
||||
Multimap<String, String> queryParams = addQueryParams(tokenValues.entries(), method, args);
|
||||
Multimap<String, String> matrixParams = addMatrixParams(tokenValues.entries(), method, args);
|
||||
Multimap<String, String> headers = buildHeaders(tokenValues.entries(), method, args);
|
||||
if (r != null)
|
||||
headers.putAll(r.getHeaders());
|
||||
|
||||
if (shouldAddHostHeader(method)) {
|
||||
StringBuilder hostHeader = new StringBuilder(endpoint.getHost());
|
||||
if (endpoint.getPort() != -1)
|
||||
hostHeader.append(":").append(endpoint.getPort());
|
||||
headers.put(HOST, hostHeader.toString());
|
||||
}
|
||||
String stringPayload = options.buildStringPayload();
|
||||
if (stringPayload != null)
|
||||
payload = Payloads.newStringPayload(stringPayload);
|
||||
}
|
||||
|
||||
if (matrixParams.size() > 0) {
|
||||
for (String key : matrixParams.keySet())
|
||||
builder.matrixParam(key, Lists.newArrayList(matrixParams.get(key)).toArray());
|
||||
}
|
||||
Payload payload = null;
|
||||
HttpRequestOptions options = findOptionsIn(method, args);
|
||||
if (options != null) {
|
||||
injector.injectMembers(options);// TODO test case
|
||||
for (Entry<String, String> header : options.buildRequestHeaders().entries()) {
|
||||
headers.put(header.getKey(), Strings2.replaceTokens(header.getValue(), tokenValues.entries()));
|
||||
}
|
||||
for (Entry<String, String> matrix : options.buildMatrixParameters().entries()) {
|
||||
matrixParams.put(matrix.getKey(), Strings2.replaceTokens(matrix.getValue(), tokenValues.entries()));
|
||||
}
|
||||
for (Entry<String, String> query : options.buildQueryParameters().entries()) {
|
||||
queryParams.put(query.getKey(), Strings2.replaceTokens(query.getValue(), tokenValues.entries()));
|
||||
}
|
||||
for (Entry<String, String> form : options.buildFormParameters().entries()) {
|
||||
formParams.put(form.getKey(), Strings2.replaceTokens(form.getValue(), tokenValues.entries()));
|
||||
}
|
||||
|
||||
if (queryParams.size() > 0) {
|
||||
builder.replaceQuery(ModifyRequest.makeQueryLine(queryParams, null, skips));
|
||||
}
|
||||
|
||||
requestBuilder.headers(filterOutContentHeaders(headers));
|
||||
|
||||
try {
|
||||
requestBuilder.endpoint(builder.buildFromEncodedMap(Maps2.convertUnsafe(tokenValues)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalStateException(e);
|
||||
} catch (UriBuilderException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
if (payload == null)
|
||||
payload = findPayloadInArgs(args);
|
||||
List<? extends Part> parts = getParts(method, args, concat(tokenValues.entries(), formParams.entries()));
|
||||
if (parts.size() > 0) {
|
||||
if (formParams.size() > 0) {
|
||||
parts = newLinkedList(concat(transform(formParams.entries(), ENTRY_TO_PART), parts));
|
||||
String pathSuffix = options.buildPathSuffix();
|
||||
if (pathSuffix != null) {
|
||||
builder.path(pathSuffix);
|
||||
}
|
||||
String stringPayload = options.buildStringPayload();
|
||||
if (stringPayload != null)
|
||||
payload = Payloads.newStringPayload(stringPayload);
|
||||
}
|
||||
payload = new MultipartForm(BOUNDARY, parts);
|
||||
} else if (formParams.size() > 0) {
|
||||
payload = Payloads.newUrlEncodedFormPayload(formParams, skips);
|
||||
} else if (headers.containsKey(CONTENT_TYPE)) {
|
||||
|
||||
if (matrixParams.size() > 0) {
|
||||
for (String key : matrixParams.keySet())
|
||||
builder.matrixParam(key, Lists.newArrayList(matrixParams.get(key)).toArray());
|
||||
}
|
||||
|
||||
if (queryParams.size() > 0) {
|
||||
builder.replaceQuery(ModifyRequest.makeQueryLine(queryParams, null, skips));
|
||||
}
|
||||
|
||||
requestBuilder.headers(filterOutContentHeaders(headers));
|
||||
|
||||
try {
|
||||
requestBuilder.endpoint(builder.buildFromEncodedMap(Maps2.convertUnsafe(tokenValues)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalStateException(e);
|
||||
} catch (UriBuilderException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
if (payload == null)
|
||||
payload = Payloads.newByteArrayPayload(new byte[] {});
|
||||
payload.getContentMetadata().setContentType(Iterables.get(headers.get(CONTENT_TYPE), 0));
|
||||
}
|
||||
if (payload != null) {
|
||||
requestBuilder.payload(payload);
|
||||
}
|
||||
GeneratedHttpRequest<T> request = requestBuilder.build();
|
||||
|
||||
org.jclouds.rest.MapBinder mapBinder = getMapPayloadBinderOrNull(method, args);
|
||||
if (mapBinder != null) {
|
||||
Map<String, String> mapParams = buildPostParams(method, args);
|
||||
if (method.isAnnotationPresent(PayloadParams.class)) {
|
||||
PayloadParams params = method.getAnnotation(PayloadParams.class);
|
||||
addMapPayload(mapParams, params, headers.entries());
|
||||
payload = findPayloadInArgs(args);
|
||||
List<? extends Part> parts = getParts(method, args, concat(tokenValues.entries(), formParams.entries()));
|
||||
if (parts.size() > 0) {
|
||||
if (formParams.size() > 0) {
|
||||
parts = newLinkedList(concat(transform(formParams.entries(), ENTRY_TO_PART), parts));
|
||||
}
|
||||
payload = new MultipartForm(BOUNDARY, parts);
|
||||
} else if (formParams.size() > 0) {
|
||||
payload = Payloads.newUrlEncodedFormPayload(formParams, skips);
|
||||
} else if (headers.containsKey(CONTENT_TYPE)) {
|
||||
if (payload == null)
|
||||
payload = Payloads.newByteArrayPayload(new byte[] {});
|
||||
payload.getContentMetadata().setContentType(Iterables.get(headers.get(CONTENT_TYPE), 0));
|
||||
}
|
||||
request = mapBinder.bindToRequest(request, mapParams);
|
||||
} else {
|
||||
request = decorateRequest(request);
|
||||
}
|
||||
if (payload != null) {
|
||||
requestBuilder.payload(payload);
|
||||
}
|
||||
GeneratedHttpRequest<T> request = requestBuilder.build();
|
||||
|
||||
if (request.getPayload() != null)
|
||||
request.getPayload().getContentMetadata().setPropertiesFromHttpHeaders(headers);
|
||||
utils.checkRequestHasRequiredProperties(request);
|
||||
return request;
|
||||
org.jclouds.rest.MapBinder mapBinder = getMapPayloadBinderOrNull(method, args);
|
||||
if (mapBinder != null) {
|
||||
Map<String, String> mapParams = buildPostParams(method, args);
|
||||
if (method.isAnnotationPresent(PayloadParams.class)) {
|
||||
PayloadParams params = method.getAnnotation(PayloadParams.class);
|
||||
addMapPayload(mapParams, params, headers.entries());
|
||||
}
|
||||
request = mapBinder.bindToRequest(request, mapParams);
|
||||
} else {
|
||||
request = decorateRequest(request);
|
||||
}
|
||||
|
||||
if (request.getPayload() != null)
|
||||
request.getPayload().getContentMetadata().setPropertiesFromHttpHeaders(headers);
|
||||
utils.checkRequestHasRequiredProperties(request);
|
||||
return request;
|
||||
} catch (ExecutionException e) {
|
||||
Throwables.propagate(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Multimap<String, String> filterOutContentHeaders(Multimap<String, String> headers) {
|
||||
// TODO make a filter like {@link Maps.filterKeys} instead of this
|
||||
ImmutableMultimap.Builder<String, String> headersBuilder = ImmutableMultimap.builder();
|
||||
// http message usually comes in as a null key header, let's filter it out.
|
||||
// http message usually comes in as a null key header, let's filter it
|
||||
// out.
|
||||
for (String header : Iterables.filter(headers.keySet(), Predicates.notNull())) {
|
||||
if (!ContentMetadata.HTTP_HEADERS.contains(header)) {
|
||||
headersBuilder.putAll(header, headers.get(header));
|
||||
|
@ -537,7 +553,7 @@ public class RestAnnotationProcessor<T> {
|
|||
|
||||
public static final String BOUNDARY = "--JCLOUDS--";
|
||||
|
||||
private Multimap<String, String> addPathAndGetTokens(Class<?> clazz, Method method, Object[] args, UriBuilder builder) {
|
||||
private Multimap<String, String> addPathAndGetTokens(Class<?> clazz, Method method, Object[] args, UriBuilder builder) throws ExecutionException {
|
||||
if (clazz.isAnnotationPresent(Path.class))
|
||||
builder.path(clazz);
|
||||
if (method.isAnnotationPresent(Path.class))
|
||||
|
@ -550,14 +566,14 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
|
||||
public static URI replaceQuery(Provider<UriBuilder> uriBuilderProvider, URI in, String newQuery,
|
||||
@Nullable Comparator<Entry<String, String>> sorter, char... skips) {
|
||||
@Nullable Comparator<Entry<String, String>> sorter, char... skips) {
|
||||
UriBuilder builder = uriBuilderProvider.get().uri(in);
|
||||
builder.replaceQuery(ModifyRequest.makeQueryLine(ModifyRequest.parseQueryToMap(newQuery), sorter, skips));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private Multimap<String, String> addMatrixParams(Collection<Entry<String, String>> tokenValues, Method method,
|
||||
Object... args) {
|
||||
Object... args) throws ExecutionException {
|
||||
Multimap<String, String> matrixMap = LinkedListMultimap.create();
|
||||
if (declaring.isAnnotationPresent(MatrixParams.class)) {
|
||||
MatrixParams matrix = declaring.getAnnotation(MatrixParams.class);
|
||||
|
@ -576,7 +592,7 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
|
||||
private Multimap<String, String> addFormParams(Collection<Entry<String, String>> tokenValues, Method method,
|
||||
Object... args) {
|
||||
Object... args) throws ExecutionException {
|
||||
Multimap<String, String> formMap = LinkedListMultimap.create();
|
||||
if (declaring.isAnnotationPresent(FormParams.class)) {
|
||||
FormParams form = declaring.getAnnotation(FormParams.class);
|
||||
|
@ -595,7 +611,7 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
|
||||
private Multimap<String, String> addQueryParams(Collection<Entry<String, String>> tokenValues, Method method,
|
||||
Object... args) {
|
||||
Object... args) throws ExecutionException {
|
||||
Multimap<String, String> queryMap = LinkedListMultimap.create();
|
||||
if (declaring.isAnnotationPresent(QueryParams.class)) {
|
||||
QueryParams query = declaring.getAnnotation(QueryParams.class);
|
||||
|
@ -614,7 +630,7 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
|
||||
private void addForm(Multimap<String, String> formParams, FormParams form,
|
||||
Collection<Entry<String, String>> tokenValues) {
|
||||
Collection<Entry<String, String>> tokenValues) {
|
||||
for (int i = 0; i < form.keys().length; i++) {
|
||||
if (form.values()[i].equals(FormParams.NULL)) {
|
||||
formParams.removeAll(form.keys()[i]);
|
||||
|
@ -626,7 +642,7 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
|
||||
private void addQuery(Multimap<String, String> queryParams, QueryParams query,
|
||||
Collection<Entry<String, String>> tokenValues) {
|
||||
Collection<Entry<String, String>> tokenValues) {
|
||||
for (int i = 0; i < query.keys().length; i++) {
|
||||
if (query.values()[i].equals(QueryParams.NULL)) {
|
||||
queryParams.removeAll(query.keys()[i]);
|
||||
|
@ -638,7 +654,7 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
|
||||
private void addMatrix(Multimap<String, String> matrixParams, MatrixParams matrix,
|
||||
Collection<Entry<String, String>> tokenValues) {
|
||||
Collection<Entry<String, String>> tokenValues) {
|
||||
for (int i = 0; i < matrix.keys().length; i++) {
|
||||
if (matrix.values()[i].equals(MatrixParams.NULL)) {
|
||||
matrixParams.removeAll(matrix.keys()[i]);
|
||||
|
@ -650,7 +666,7 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
|
||||
private void addMapPayload(Map<String, String> postParams, PayloadParams mapDefaults,
|
||||
Collection<Entry<String, String>> tokenValues) {
|
||||
Collection<Entry<String, String>> tokenValues) {
|
||||
for (int i = 0; i < mapDefaults.keys().length; i++) {
|
||||
if (mapDefaults.values()[i].equals(PayloadParams.NULL)) {
|
||||
postParams.put(mapDefaults.keys()[i], null);
|
||||
|
@ -683,9 +699,10 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static URI getEndpointInParametersOrNull(Method method, final Object[] args, Injector injector) {
|
||||
public static URI getEndpointInParametersOrNull(Method method, final Object[] args, Injector injector)
|
||||
throws ExecutionException {
|
||||
Map<Integer, Set<Annotation>> map = indexWithAtLeastOneAnnotation(method,
|
||||
methodToIndexOfParamToEndpointParamAnnotations);
|
||||
methodToIndexOfParamToEndpointParamAnnotations);
|
||||
if (map.size() >= 1 && args.length > 0) {
|
||||
EndpointParam firstAnnotation = (EndpointParam) get(get(map.values(), 0), 0);
|
||||
Function<Object, URI> parser = injector.getInstance(firstAnnotation.parser());
|
||||
|
@ -694,8 +711,8 @@ public class RestAnnotationProcessor<T> {
|
|||
int index = map.keySet().iterator().next();
|
||||
try {
|
||||
URI returnVal = parser.apply(args[index]);
|
||||
checkArgument(returnVal != null, String.format("endpoint for [%s] not configured for %s", args[index],
|
||||
method));
|
||||
checkArgument(returnVal != null,
|
||||
String.format("endpoint for [%s] not configured for %s", args[index], method));
|
||||
return returnVal;
|
||||
} catch (NullPointerException e) {
|
||||
throw new IllegalArgumentException(String.format("argument at index %d on method %s", index, method), e);
|
||||
|
@ -712,19 +729,19 @@ public class RestAnnotationProcessor<T> {
|
|||
});
|
||||
try {
|
||||
URI returnVal = parser.apply(argsToParse);
|
||||
checkArgument(returnVal != null, String.format("endpoint for [%s] not configured for %s", argsToParse,
|
||||
method));
|
||||
checkArgument(returnVal != null,
|
||||
String.format("endpoint for [%s] not configured for %s", argsToParse, method));
|
||||
return returnVal;
|
||||
} catch (NullPointerException e) {
|
||||
throw new IllegalArgumentException(String.format("illegal argument in [%s] for method %s", argsToParse,
|
||||
method), e);
|
||||
method), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static URI getEndpointFor(Method method, Object[] args, Injector injector) {
|
||||
public static URI getEndpointFor(Method method, Object[] args, Injector injector) throws ExecutionException {
|
||||
URI endpoint = getEndpointInParametersOrNull(method, args, injector);
|
||||
if (endpoint == null) {
|
||||
Endpoint annotation;
|
||||
|
@ -753,29 +770,29 @@ public class RestAnnotationProcessor<T> {
|
|||
public static final TypeLiteral<ListenableFuture<HttpResponse>> futureHttpResponseLiteral = new TypeLiteral<ListenableFuture<HttpResponse>>() {
|
||||
};
|
||||
|
||||
@SuppressWarnings( { "unchecked", "rawtypes" })
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public static Key<? extends Function<HttpResponse, ?>> getParserOrThrowException(Method method) {
|
||||
ResponseParser annotation = method.getAnnotation(ResponseParser.class);
|
||||
if (annotation == null) {
|
||||
if (method.getReturnType().equals(void.class)
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureVoidLiteral)) {
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureVoidLiteral)) {
|
||||
return Key.get(ReleasePayloadAndReturn.class);
|
||||
} else if (method.getReturnType().equals(boolean.class) || method.getReturnType().equals(Boolean.class)
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureBooleanLiteral)) {
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureBooleanLiteral)) {
|
||||
return Key.get(ReturnTrueIf2xx.class);
|
||||
} else if (method.getReturnType().equals(InputStream.class)
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureInputStreamLiteral)) {
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureInputStreamLiteral)) {
|
||||
return Key.get(ReturnInputStream.class);
|
||||
} else if (method.getReturnType().equals(HttpResponse.class)
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureHttpResponseLiteral)) {
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureHttpResponseLiteral)) {
|
||||
return Key.get((Class) IdentityFunction.class);
|
||||
} else if (getAcceptHeadersOrNull(method).contains(MediaType.APPLICATION_JSON)) {
|
||||
return getJsonParserKeyForMethod(method);
|
||||
} else if (method.getReturnType().equals(String.class)
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureStringLiteral)) {
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureStringLiteral)) {
|
||||
return Key.get(ReturnStringIf2xx.class);
|
||||
} else if (method.getReturnType().equals(URI.class)
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureURILiteral)) {
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureURILiteral)) {
|
||||
return Key.get(ParseURIFromListOrLocationHeaderIf20x.class);
|
||||
} else {
|
||||
throw new IllegalStateException("You must specify a ResponseParser annotation on: " + method.toString());
|
||||
|
@ -804,7 +821,7 @@ public class RestAnnotationProcessor<T> {
|
|||
return returnVal;
|
||||
}
|
||||
|
||||
@SuppressWarnings( { "unchecked", "rawtypes" })
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public static Key<? extends Function<HttpResponse, ?>> getJsonParserKeyForMethodAnType(Method method, Type returnVal) {
|
||||
ParameterizedType parserType;
|
||||
if (method.isAnnotationPresent(Unwrap.class)) {
|
||||
|
@ -820,7 +837,7 @@ public class RestAnnotationProcessor<T> {
|
|||
parserType = Types.newParameterizedType(UnwrapOnlyNestedJsonValueInSet.class, returnVal);
|
||||
else
|
||||
throw new IllegalStateException(String.format("depth(%d) edgeCollection(%s) not yet supported for @Unwrap",
|
||||
depth, edgeCollection));
|
||||
depth, edgeCollection));
|
||||
} else {
|
||||
parserType = Types.newParameterizedType(ParseJson.class, returnVal);
|
||||
}
|
||||
|
@ -850,7 +867,7 @@ public class RestAnnotationProcessor<T> {
|
|||
} else {
|
||||
if (postBinders[0] instanceof org.jclouds.rest.MapBinder) {
|
||||
throw new IllegalArgumentException("we currently do not support multiple varargs postBinders in: "
|
||||
+ method.getName());
|
||||
+ method.getName());
|
||||
}
|
||||
}
|
||||
} else if (arg instanceof org.jclouds.rest.MapBinder) {
|
||||
|
@ -883,8 +900,8 @@ public class RestAnnotationProcessor<T> {
|
|||
Set<String> requests = getHttpMethods(method);
|
||||
if (requests == null || requests.size() != 1) {
|
||||
throw new IllegalStateException(
|
||||
"You must use at least one, but no more than one http method or pathparam annotation on: "
|
||||
+ method.toString());
|
||||
"You must use at least one, but no more than one http method or pathparam annotation on: "
|
||||
+ method.toString());
|
||||
}
|
||||
return requests.iterator().next();
|
||||
}
|
||||
|
@ -902,11 +919,13 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
};
|
||||
|
||||
public GeneratedHttpRequest<T> decorateRequest(GeneratedHttpRequest<T> request) {
|
||||
public GeneratedHttpRequest<T> decorateRequest(GeneratedHttpRequest<T> request) throws NegativeArraySizeException,
|
||||
ExecutionException {
|
||||
OUTER: for (Entry<Integer, Set<Annotation>> entry : concat(//
|
||||
filterValues(methodToIndexOfParamToBinderParamAnnotation.get(request.getJavaMethod()), notEmpty)
|
||||
.entrySet(), //
|
||||
filterValues(methodToIndexOfParamToWrapWithAnnotation.get(request.getJavaMethod()), notEmpty).entrySet())) {
|
||||
filterValues(methodToIndexOfParamToBinderParamAnnotation.get(request.getJavaMethod()).asMap(), notEmpty)
|
||||
.entrySet(), //
|
||||
filterValues(methodToIndexOfParamToWrapWithAnnotation.get(request.getJavaMethod()).asMap(), notEmpty)
|
||||
.entrySet())) {
|
||||
boolean shouldBreak = false;
|
||||
Annotation annotation = Iterables.get(entry.getValue(), 0);
|
||||
Binder binder;
|
||||
|
@ -914,7 +933,7 @@ public class RestAnnotationProcessor<T> {
|
|||
binder = injector.getInstance(BinderParam.class.cast(annotation).value());
|
||||
else
|
||||
binder = injector.getInstance(BindToJsonPayloadWrappedWith.Factory.class).create(
|
||||
WrapWith.class.cast(annotation).value());
|
||||
WrapWith.class.cast(annotation).value());
|
||||
if (request.getArgs().size() >= entry.getKey() + 1 && request.getArgs().get(entry.getKey()) != null) {
|
||||
Object input;
|
||||
Class<?> parameterType = request.getJavaMethod().getParameterTypes()[entry.getKey()];
|
||||
|
@ -947,28 +966,28 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
|
||||
public static Map<Integer, Set<Annotation>> indexWithOnlyOneAnnotation(Method method, String description,
|
||||
Map<Method, Map<Integer, Set<Annotation>>> toRefine) {
|
||||
Cache<Method, Cache<Integer, Set<Annotation>>> toRefine) throws ExecutionException {
|
||||
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = indexWithAtLeastOneAnnotation(method, toRefine);
|
||||
if (indexToPayloadAnnotation.size() > 1) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"You must not specify more than one %s annotation on: %s; found %s", description, method.toString(),
|
||||
indexToPayloadAnnotation));
|
||||
"You must not specify more than one %s annotation on: %s; found %s", description, method.toString(),
|
||||
indexToPayloadAnnotation));
|
||||
}
|
||||
return indexToPayloadAnnotation;
|
||||
}
|
||||
|
||||
private static Map<Integer, Set<Annotation>> indexWithAtLeastOneAnnotation(Method method,
|
||||
Map<Method, Map<Integer, Set<Annotation>>> toRefine) {
|
||||
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = filterValues(toRefine.get(method),
|
||||
new Predicate<Set<Annotation>>() {
|
||||
public boolean apply(Set<Annotation> input) {
|
||||
return input.size() == 1;
|
||||
}
|
||||
});
|
||||
Cache<Method, Cache<Integer, Set<Annotation>>> toRefine) throws ExecutionException {
|
||||
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = filterValues(toRefine.get(method).asMap(),
|
||||
new Predicate<Set<Annotation>>() {
|
||||
public boolean apply(Set<Annotation> input) {
|
||||
return input.size() == 1;
|
||||
}
|
||||
});
|
||||
return indexToPayloadAnnotation;
|
||||
}
|
||||
|
||||
private HttpRequestOptions findOptionsIn(Method method, Object... args) {
|
||||
private HttpRequestOptions findOptionsIn(Method method, Object... args) throws ExecutionException {
|
||||
for (int index : methodToIndexesOfOptions.get(method)) {
|
||||
if (args.length >= index + 1) {// accomodate varargs
|
||||
if (args[index] instanceof Object[]) {
|
||||
|
@ -983,7 +1002,7 @@ public class RestAnnotationProcessor<T> {
|
|||
} else {
|
||||
if (options[0] instanceof HttpRequestOptions) {
|
||||
throw new IllegalArgumentException("we currently do not support multiple varargs options in: "
|
||||
+ method.getName());
|
||||
+ method.getName());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -995,11 +1014,11 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
|
||||
public Multimap<String, String> buildHeaders(Collection<Entry<String, String>> tokenValues, Method method,
|
||||
final Object... args) {
|
||||
final Object... args) throws ExecutionException {
|
||||
Multimap<String, String> headers = LinkedHashMultimap.create();
|
||||
addHeaderIfAnnotationPresentOnMethod(headers, method, tokenValues);
|
||||
Map<Integer, Set<Annotation>> indexToHeaderParam = methodToIndexOfParamToHeaderParamAnnotations.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToHeaderParam.entrySet()) {
|
||||
Cache<Integer, Set<Annotation>> indexToHeaderParam = methodToIndexOfParamToHeaderParamAnnotations.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToHeaderParam.asMap().entrySet()) {
|
||||
for (Annotation key : entry.getValue()) {
|
||||
String value = args[entry.getKey()].toString();
|
||||
value = Strings2.replaceTokens(value, tokenValues);
|
||||
|
@ -1042,7 +1061,7 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
|
||||
public void addHeaderIfAnnotationPresentOnMethod(Multimap<String, String> headers, Method method,
|
||||
Collection<Entry<String, String>> tokenValues) {
|
||||
Collection<Entry<String, String>> tokenValues) {
|
||||
if (declaring.isAnnotationPresent(Headers.class)) {
|
||||
Headers header = declaring.getAnnotation(Headers.class);
|
||||
addHeader(headers, header, tokenValues);
|
||||
|
@ -1054,7 +1073,7 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
|
||||
private void addHeader(Multimap<String, String> headers, Headers header,
|
||||
Collection<Entry<String, String>> tokenValues) {
|
||||
Collection<Entry<String, String>> tokenValues) {
|
||||
for (int i = 0; i < header.keys().length; i++) {
|
||||
String value = header.values()[i];
|
||||
value = Strings2.replaceTokens(value, tokenValues);
|
||||
|
@ -1063,10 +1082,10 @@ public class RestAnnotationProcessor<T> {
|
|||
|
||||
}
|
||||
|
||||
List<? extends Part> getParts(Method method, Object[] args, Iterable<Entry<String, String>> iterable) {
|
||||
List<? extends Part> getParts(Method method, Object[] args, Iterable<Entry<String, String>> iterable) throws ExecutionException {
|
||||
List<Part> parts = newLinkedList();
|
||||
Map<Integer, Set<Annotation>> indexToPartParam = methodToIndexOfParamToPartParamAnnotations.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToPartParam.entrySet()) {
|
||||
Cache<Integer, Set<Annotation>> indexToPartParam = methodToIndexOfParamToPartParamAnnotations.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToPartParam.asMap().entrySet()) {
|
||||
for (Annotation key : entry.getValue()) {
|
||||
PartParam param = (PartParam) key;
|
||||
PartOptions options = new PartOptions();
|
||||
|
@ -1101,12 +1120,12 @@ public class RestAnnotationProcessor<T> {
|
|||
return null;
|
||||
}
|
||||
|
||||
private Multimap<String, String> getPathParamKeyValues(Method method, Object... args) {
|
||||
private Multimap<String, String> getPathParamKeyValues(Method method, Object... args) throws ExecutionException {
|
||||
Multimap<String, String> pathParamValues = LinkedHashMultimap.create();
|
||||
Map<Integer, Set<Annotation>> indexToPathParam = methodToIndexOfParamToPathParamAnnotations.get(method);
|
||||
Cache<Integer, Set<Annotation>> indexToPathParam = methodToIndexOfParamToPathParamAnnotations.get(method);
|
||||
|
||||
Map<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToPathParam.entrySet()) {
|
||||
Cache<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToPathParam.asMap().entrySet()) {
|
||||
for (Annotation key : entry.getValue()) {
|
||||
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
|
||||
String paramKey = ((PathParam) key).value();
|
||||
|
@ -1138,12 +1157,12 @@ public class RestAnnotationProcessor<T> {
|
|||
return encoded;
|
||||
}
|
||||
|
||||
private Multimap<String, String> getMatrixParamKeyValues(Method method, Object... args) {
|
||||
private Multimap<String, String> getMatrixParamKeyValues(Method method, Object... args) throws ExecutionException {
|
||||
Multimap<String, String> matrixParamValues = LinkedHashMultimap.create();
|
||||
Map<Integer, Set<Annotation>> indexToMatrixParam = methodToIndexOfParamToMatrixParamAnnotations.get(method);
|
||||
Cache<Integer, Set<Annotation>> indexToMatrixParam = methodToIndexOfParamToMatrixParamAnnotations.get(method);
|
||||
|
||||
Map<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToMatrixParam.entrySet()) {
|
||||
Cache<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToMatrixParam.asMap().entrySet()) {
|
||||
for (Annotation key : entry.getValue()) {
|
||||
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
|
||||
String paramKey = ((MatrixParam) key).value();
|
||||
|
@ -1167,12 +1186,12 @@ public class RestAnnotationProcessor<T> {
|
|||
return matrixParamValues;
|
||||
}
|
||||
|
||||
private Multimap<String, String> getFormParamKeyValues(Method method, Object... args) {
|
||||
private Multimap<String, String> getFormParamKeyValues(Method method, Object... args) throws ExecutionException {
|
||||
Multimap<String, String> formParamValues = LinkedHashMultimap.create();
|
||||
Map<Integer, Set<Annotation>> indexToFormParam = methodToIndexOfParamToFormParamAnnotations.get(method);
|
||||
Cache<Integer, Set<Annotation>> indexToFormParam = methodToIndexOfParamToFormParamAnnotations.get(method);
|
||||
|
||||
Map<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToFormParam.entrySet()) {
|
||||
Cache<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToFormParam.asMap().entrySet()) {
|
||||
for (Annotation key : entry.getValue()) {
|
||||
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
|
||||
String paramKey = ((FormParam) key).value();
|
||||
|
@ -1196,12 +1215,12 @@ public class RestAnnotationProcessor<T> {
|
|||
return formParamValues;
|
||||
}
|
||||
|
||||
private Multimap<String, String> getQueryParamKeyValues(Method method, Object... args) {
|
||||
private Multimap<String, String> getQueryParamKeyValues(Method method, Object... args) throws ExecutionException {
|
||||
Multimap<String, String> queryParamValues = LinkedHashMultimap.create();
|
||||
Map<Integer, Set<Annotation>> indexToQueryParam = methodToIndexOfParamToQueryParamAnnotations.get(method);
|
||||
Cache<Integer, Set<Annotation>> indexToQueryParam = methodToIndexOfParamToQueryParamAnnotations.get(method);
|
||||
|
||||
Map<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToQueryParam.entrySet()) {
|
||||
Cache<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToQueryParam.asMap().entrySet()) {
|
||||
for (Annotation key : entry.getValue()) {
|
||||
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
|
||||
String paramKey = ((QueryParam) key).value();
|
||||
|
@ -1225,11 +1244,11 @@ public class RestAnnotationProcessor<T> {
|
|||
return queryParamValues;
|
||||
}
|
||||
|
||||
private Map<String, String> buildPostParams(Method method, Object... args) {
|
||||
private Map<String, String> buildPostParams(Method method, Object... args) throws ExecutionException {
|
||||
Map<String, String> postParams = newHashMap();
|
||||
Map<Integer, Set<Annotation>> indexToPathParam = methodToIndexOfParamToPostParamAnnotations.get(method);
|
||||
Map<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToPathParam.entrySet()) {
|
||||
Cache<Integer, Set<Annotation>> indexToPathParam = methodToIndexOfParamToPostParamAnnotations.get(method);
|
||||
Cache<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToPathParam.asMap().entrySet()) {
|
||||
for (Annotation key : entry.getValue()) {
|
||||
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
|
||||
String paramKey = ((PayloadParam) key).value();
|
||||
|
|
|
@ -36,6 +36,7 @@ import static org.jclouds.rest.internal.RestAnnotationProcessor.methodToIndexOfP
|
|||
import static org.jclouds.rest.internal.RestAnnotationProcessor.methodToIndexesOfOptions;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Named;
|
||||
|
@ -48,7 +49,7 @@ import org.jclouds.logging.Logger;
|
|||
import org.jclouds.rest.annotations.Delegate;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessor.MethodKey;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.inject.Inject;
|
||||
|
@ -63,7 +64,7 @@ import com.google.inject.Provides;
|
|||
*/
|
||||
|
||||
@Singleton
|
||||
public class SeedAnnotationCache implements Function<Class<?>, Boolean> {
|
||||
public class SeedAnnotationCache extends CacheLoader<Class<?>, Boolean> {
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
|
@ -82,7 +83,8 @@ public class SeedAnnotationCache implements Function<Class<?>, Boolean> {
|
|||
constants.put(key, value);
|
||||
}
|
||||
|
||||
public Boolean apply(Class<?> declaring) {
|
||||
@Override
|
||||
public Boolean load(Class<?> declaring) throws ExecutionException {
|
||||
for (Method method : difference(ImmutableSet.copyOf(declaring.getMethods()), ImmutableSet.copyOf(Object.class
|
||||
.getMethods()))) {
|
||||
if (isHttpMethod(method) || method.isAnnotationPresent(Delegate.class)) {
|
||||
|
|
|
@ -20,11 +20,12 @@ package org.jclouds.util;
|
|||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -43,36 +44,38 @@ public class Patterns {
|
|||
public static final Pattern _7E_PATTERN = Pattern.compile("%7E");
|
||||
public static final Pattern NEWLINE_PATTERN = Pattern.compile("\r?\n");
|
||||
public static final Pattern SLASH_PATTERN = Pattern.compile("[/]");
|
||||
public static final Pattern IP_PATTERN = Pattern
|
||||
.compile("b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).)"
|
||||
+ "{3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)b");
|
||||
public static final Pattern IP_PATTERN = Pattern.compile("b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).)"
|
||||
+ "{3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)b");
|
||||
public static final Pattern LEADING_SLASHES = Pattern.compile("^[/]+");
|
||||
public static final Pattern TRAILING_SLASHES = Pattern.compile("[/]*$");
|
||||
public static final Pattern REST_CONTEXT_BUILDER = Pattern.compile("(.*ContextBuilder)<([^,]+), ?([^>]+)>");
|
||||
|
||||
public final static Map<Character, Pattern> CHAR_TO_ENCODED_PATTERN = new MapMaker()
|
||||
.makeComputingMap(new Function<Character, Pattern>() {
|
||||
public Pattern apply(Character plain) {
|
||||
try {
|
||||
String encoded = URLEncoder.encode(plain + "", "UTF-8");
|
||||
return Pattern.compile(encoded);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new IllegalStateException("Bad encoding on input: " + plain, e);
|
||||
}
|
||||
public final static Cache<Character, Pattern> CHAR_TO_ENCODED_PATTERN = CacheBuilder.newBuilder()
|
||||
.<Character, Pattern> build(new CacheLoader<Character, Pattern>() {
|
||||
@Override
|
||||
public Pattern load(Character plain) throws ExecutionException {
|
||||
try {
|
||||
String encoded = URLEncoder.encode(plain + "", "UTF-8");
|
||||
return Pattern.compile(encoded);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new ExecutionException("Bad encoding on input: " + plain, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
public final static Map<Character, Pattern> CHAR_TO_PATTERN = new MapMaker()
|
||||
.makeComputingMap(new Function<Character, Pattern>() {
|
||||
public Pattern apply(Character plain) {
|
||||
return Pattern.compile(plain + "");
|
||||
}
|
||||
});
|
||||
public final static Cache<Character, Pattern> CHAR_TO_PATTERN = CacheBuilder.newBuilder()
|
||||
.<Character, Pattern> build(new CacheLoader<Character, Pattern>() {
|
||||
@Override
|
||||
public Pattern load(Character plain) {
|
||||
return Pattern.compile(plain + "");
|
||||
}
|
||||
});
|
||||
|
||||
public final static Map<String, Pattern> TOKEN_TO_PATTERN = new MapMaker()
|
||||
.makeComputingMap(new Function<String, Pattern>() {
|
||||
public Pattern apply(String tokenValue) {
|
||||
return Pattern.compile("\\{" + tokenValue + "\\}");
|
||||
}
|
||||
});
|
||||
public final static Cache<String, Pattern> TOKEN_TO_PATTERN = CacheBuilder.newBuilder()
|
||||
.<String, Pattern> build(new CacheLoader<String, Pattern>() {
|
||||
@Override
|
||||
public Pattern load(String tokenValue) {
|
||||
return Pattern.compile("\\{" + tokenValue + "\\}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import java.net.URLDecoder;
|
|||
import java.net.URLEncoder;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
@ -70,6 +71,8 @@ public class Strings2 {
|
|||
return returnVal;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new IllegalStateException("Bad encoding on input: " + in, e);
|
||||
} catch (ExecutionException e) {
|
||||
throw new IllegalStateException("error creating pattern: " + in, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,7 +90,11 @@ public class Strings2 {
|
|||
|
||||
public static String replaceTokens(String value, Iterable<Entry<String, String>> tokenValues) {
|
||||
for (Entry<String, String> tokenValue : tokenValues) {
|
||||
value = Strings2.replaceAll(value, TOKEN_TO_PATTERN.get(tokenValue.getKey()), tokenValue.getValue());
|
||||
try {
|
||||
value = Strings2.replaceAll(value, TOKEN_TO_PATTERN.get(tokenValue.getKey()), tokenValue.getValue());
|
||||
} catch (ExecutionException e) {
|
||||
throw new IllegalStateException("error creating pattern: " + tokenValue.getKey(), e);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
@ -107,7 +114,11 @@ public class Strings2 {
|
|||
|
||||
public static String replaceAll(String input, char match, String replacement) {
|
||||
if (input.indexOf(match) != -1) {
|
||||
input = CHAR_TO_PATTERN.get(match).matcher(input).replaceAll(replacement);
|
||||
try {
|
||||
input = CHAR_TO_PATTERN.get(match).matcher(input).replaceAll(replacement);
|
||||
} catch (ExecutionException e) {
|
||||
throw new IllegalStateException("error creating pattern: " + match, e);
|
||||
}
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
|
|
@ -88,8 +88,8 @@ public class Throwables2 {
|
|||
throw (Exception) throwable;
|
||||
}
|
||||
}
|
||||
Throwables.throwCause(exception, true);
|
||||
return exception;
|
||||
Throwables.propagateIfPossible(exception.getCause(), Exception.class);
|
||||
throw exception;
|
||||
}
|
||||
|
||||
public static <T> T propagateAuthorizationOrOriginalException(Exception e) {
|
||||
|
|
|
@ -67,7 +67,7 @@ import com.google.common.collect.Sets;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "performance", enabled = false, sequential = true, testName = "FuturesTransformPerformanceTest")
|
||||
@Test(groups = "performance", enabled = false, singleThreaded = true, testName = "FuturesTransformPerformanceTest")
|
||||
public class FuturesTransformPerformanceTest {
|
||||
private static final int FUDGE = 5;
|
||||
private static final int COUNT = 100;
|
||||
|
@ -175,7 +175,7 @@ public class FuturesTransformPerformanceTest {
|
|||
long start = System.currentTimeMillis();
|
||||
Map<String, Future<Long>> responses = newHashMap();
|
||||
for (int i = 0; i < COUNT; i++)
|
||||
responses.put(i + "", Futures.transform(Futures.makeListenable(simultateIO(), chainExecutor),
|
||||
responses.put(i + "", Futures.transform(JdkFutureAdapters.listenInPoolThread(simultateIO(), chainExecutor),
|
||||
new Function<Long, Long>() {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -25,7 +25,6 @@ import java.io.IOException;
|
|||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -36,6 +35,10 @@ import org.jclouds.internal.ClassMethodArgs;
|
|||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Functions;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
@ -162,8 +165,8 @@ public class SyncProxyTest {
|
|||
|
||||
@BeforeTest
|
||||
public void setUp() throws IllegalArgumentException, SecurityException, NoSuchMethodException {
|
||||
sync = SyncProxy.proxy(Sync.class, new SyncProxy(Sync.class, new Async(),
|
||||
new ConcurrentHashMap<ClassMethodArgs, Object>(), ImmutableMap.<Class<?>, Class<?>> of()));
|
||||
Cache<ClassMethodArgs, Object> cache = CacheBuilder.newBuilder().build(CacheLoader.from(Functions.<Object>constant(null)));
|
||||
sync = SyncProxy.proxy(Sync.class, new SyncProxy(Sync.class, new Async(),cache, ImmutableMap.<Class<?>, Class<?>> of()));
|
||||
// just to warm up
|
||||
sync.string();
|
||||
}
|
||||
|
@ -225,8 +228,9 @@ public class SyncProxyTest {
|
|||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testWrongTypedException() throws IllegalArgumentException, SecurityException, NoSuchMethodException,
|
||||
IOException {
|
||||
Cache<ClassMethodArgs, Object> cache = CacheBuilder.newBuilder().build(CacheLoader.from(Functions.<Object>constant(null)));
|
||||
SyncProxy.proxy(SyncWrongException.class, new SyncProxy(SyncWrongException.class, new Async(),
|
||||
new ConcurrentHashMap<ClassMethodArgs, Object>(), ImmutableMap.<Class<?>, Class<?>> of()));
|
||||
cache, ImmutableMap.<Class<?>, Class<?>> of()));
|
||||
}
|
||||
|
||||
private static interface SyncNoTimeOut {
|
||||
|
@ -243,8 +247,9 @@ public class SyncProxyTest {
|
|||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testNoTimeOutException() throws IllegalArgumentException, SecurityException, NoSuchMethodException,
|
||||
IOException {
|
||||
Cache<ClassMethodArgs, Object> cache = CacheBuilder.newBuilder().build(CacheLoader.from(Functions.<Object>constant(null)));
|
||||
SyncProxy.proxy(SyncNoTimeOut.class, new SyncProxy(SyncNoTimeOut.class, new Async(),
|
||||
new ConcurrentHashMap<ClassMethodArgs, Object>(), ImmutableMap.<Class<?>, Class<?>> of()));
|
||||
cache, ImmutableMap.<Class<?>, Class<?>> of()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* 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.functions;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", singleThreaded = true, testName = "CacheLearningTest")
|
||||
public class CacheLearningTest {
|
||||
@Test
|
||||
public void howTo() throws ExecutionException {
|
||||
Cache<String, String> cache = CacheBuilder.newBuilder().build(new CacheLoader<String, String>() {
|
||||
|
||||
@Override
|
||||
public String load(String key) throws Exception {
|
||||
if (key.equals("runtimeexception"))
|
||||
throw new RuntimeException("runtimeexception");
|
||||
if (key.equals("exception"))
|
||||
throw new Exception("exception");
|
||||
return key.equals("foo") ? null : key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "testLoader";
|
||||
}
|
||||
|
||||
});
|
||||
try {
|
||||
cache.get("foo");
|
||||
} catch (NullPointerException e) {
|
||||
assertEquals(e.getMessage(), "testLoader returned null for key foo.");
|
||||
}
|
||||
try {
|
||||
cache.get("exception");
|
||||
} catch (ExecutionException e) {
|
||||
assertEquals(e.getMessage(), "java.lang.Exception: exception");
|
||||
}
|
||||
try {
|
||||
cache.get("runtimeexception");
|
||||
} catch (UncheckedExecutionException e) {
|
||||
assertEquals(e.getMessage(), "java.lang.RuntimeException: runtimeexception");
|
||||
}
|
||||
try {
|
||||
cache.getUnchecked("exception");
|
||||
} catch (UncheckedExecutionException e) {
|
||||
assertEquals(e.getMessage(), "java.lang.Exception: exception");
|
||||
}
|
||||
assertEquals(cache.get("bar"), "bar");
|
||||
assertEquals(cache.get("baz"), "baz");
|
||||
assertEquals(cache.asMap().size(), 2);
|
||||
}
|
||||
}
|
|
@ -2157,7 +2157,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testOneHeader() throws SecurityException, NoSuchMethodException {
|
||||
public void testOneHeader() throws SecurityException, NoSuchMethodException, ExecutionException {
|
||||
Method method = TestHeaders.class.getMethod("oneHeader", String.class);
|
||||
Multimap<String, String> headers = factory(TestHeaders.class).buildHeaders(
|
||||
ImmutableMultimap.<String, String> of().entries(), method, "robot");
|
||||
|
@ -2166,7 +2166,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testOneIntHeader() throws SecurityException, NoSuchMethodException {
|
||||
public void testOneIntHeader() throws SecurityException, NoSuchMethodException, ExecutionException {
|
||||
Method method = TestHeaders.class.getMethod("oneIntHeader", int.class);
|
||||
Multimap<String, String> headers = factory(TestHeaders.class).buildHeaders(
|
||||
ImmutableMultimap.<String, String> of().entries(), method, 1);
|
||||
|
@ -2175,7 +2175,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testTwoDifferentHeaders() throws SecurityException, NoSuchMethodException {
|
||||
public void testTwoDifferentHeaders() throws SecurityException, NoSuchMethodException, ExecutionException {
|
||||
Method method = TestHeaders.class.getMethod("twoDifferentHeaders", String.class, String.class);
|
||||
Multimap<String, String> headers = factory(TestHeaders.class).buildHeaders(
|
||||
ImmutableMultimap.<String, String> of().entries(), method, "robot", "egg");
|
||||
|
@ -2185,7 +2185,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testTwoSameHeaders() throws SecurityException, NoSuchMethodException {
|
||||
public void testTwoSameHeaders() throws SecurityException, NoSuchMethodException, ExecutionException {
|
||||
Method method = TestHeaders.class.getMethod("twoSameHeaders", String.class, String.class);
|
||||
Multimap<String, String> headers = factory(TestHeaders.class).buildHeaders(
|
||||
ImmutableMultimap.<String, String> of().entries(), method, "robot", "egg");
|
||||
|
@ -2228,7 +2228,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
|
|||
|
||||
@SuppressWarnings("static-access")
|
||||
@Test
|
||||
public void testOneEndpointParam() throws SecurityException, NoSuchMethodException {
|
||||
public void testOneEndpointParam() throws SecurityException, NoSuchMethodException, ExecutionException {
|
||||
Method method = TestEndpointParams.class.getMethod("oneEndpointParam", String.class);
|
||||
URI uri = factory(TestEndpointParams.class).getEndpointInParametersOrNull(method, new Object[] { "robot" },
|
||||
injector);
|
||||
|
@ -2238,7 +2238,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
|
|||
|
||||
@SuppressWarnings("static-access")
|
||||
@Test
|
||||
public void testTwoDifferentEndpointParams() throws SecurityException, NoSuchMethodException {
|
||||
public void testTwoDifferentEndpointParams() throws SecurityException, NoSuchMethodException, ExecutionException {
|
||||
Method method = TestEndpointParams.class.getMethod("twoEndpointParams", String.class, String.class);
|
||||
URI uri = factory(TestEndpointParams.class).getEndpointInParametersOrNull(method,
|
||||
new Object[] { "robot", "egg" }, injector);
|
||||
|
|
|
@ -64,6 +64,7 @@ import org.jclouds.util.Preconditions2;
|
|||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.Cache;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
|
@ -71,7 +72,7 @@ import com.google.common.base.Supplier;
|
|||
@Singleton
|
||||
public class AWSEC2ComputeService extends EC2ComputeService {
|
||||
|
||||
private final Map<RegionAndName, String> placementGroupMap;
|
||||
private final Cache<RegionAndName, String> placementGroupMap;
|
||||
private final Predicate<PlacementGroup> placementGroupDeleted;
|
||||
private final AWSEC2Client ec2Client;
|
||||
|
||||
|
@ -90,8 +91,8 @@ public class AWSEC2ComputeService extends EC2ComputeService {
|
|||
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
|
||||
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, AWSEC2Client ec2Client,
|
||||
Map<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") Map<RegionAndName, String> securityGroupMap,
|
||||
@Named("PLACEMENT") Map<RegionAndName, String> placementGroupMap,
|
||||
Cache<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") Cache<RegionAndName, String> securityGroupMap,
|
||||
@Named("PLACEMENT") Cache<RegionAndName, String> placementGroupMap,
|
||||
@Named("DELETED") Predicate<PlacementGroup> placementGroupDeleted) {
|
||||
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
|
||||
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy,
|
||||
|
@ -117,7 +118,7 @@ public class AWSEC2ComputeService extends EC2ComputeService {
|
|||
checkState(
|
||||
placementGroupDeleted.apply(new PlacementGroup(region, placementGroup, "cluster", State.PENDING)),
|
||||
String.format("placementGroup region(%s) name(%s) failed to delete", region, placementGroup));
|
||||
placementGroupMap.remove(new RegionAndName(region, placementGroup));
|
||||
placementGroupMap.invalidate(new RegionAndName(region, placementGroup));
|
||||
logger.debug("<< deleted placementGroup(%s)", placementGroup);
|
||||
} catch (IllegalStateException e) {
|
||||
logger.debug("<< inUse placementGroup(%s)", placementGroup);
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.aws.ec2.compute;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
@ -35,6 +34,7 @@ import org.jclouds.ec2.compute.domain.RegionAndName;
|
|||
import org.jclouds.ec2.compute.internal.EC2TemplateBuilderImpl;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.Cache;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -46,7 +46,7 @@ public class AWSEC2TemplateBuilderImpl extends EC2TemplateBuilderImpl {
|
|||
protected AWSEC2TemplateBuilderImpl(@Memoized Supplier<Set<? extends Location>> locations,
|
||||
@Memoized Supplier<Set<? extends Image>> images, @Memoized Supplier<Set<? extends Hardware>> sizes,
|
||||
Supplier<Location> defaultLocation, @Named("DEFAULT") Provider<TemplateOptions> optionsProvider,
|
||||
@Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider, Map<RegionAndName, Image> imageMap) {
|
||||
@Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider, Supplier<Cache<RegionAndName, ? extends Image>> imageMap) {
|
||||
super(locations, images, sizes, defaultLocation, optionsProvider, defaultTemplateProvider, imageMap);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,6 @@ package org.jclouds.aws.ec2.compute.config;
|
|||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||
import static org.jclouds.compute.domain.OsFamily.AMZN_LINUX;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
|
@ -56,6 +54,7 @@ import org.jclouds.ec2.compute.suppliers.EC2HardwareSupplier;
|
|||
import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Provides;
|
||||
|
||||
|
@ -89,12 +88,12 @@ public class AWSEC2ComputeServiceContextModule extends BaseComputeServiceContext
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected Supplier<Map<RegionAndName, ? extends Image>> provideRegionAndNameToImageSupplierCache(
|
||||
protected Supplier<Cache<RegionAndName, ? extends Image>> provideRegionAndNameToImageSupplierCache(
|
||||
@Named(PROPERTY_SESSION_INTERVAL) long seconds, final AWSRegionAndNameToImageSupplier supplier) {
|
||||
return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<RegionAndName, ? extends Image>>(
|
||||
authException, seconds, new Supplier<Map<RegionAndName, ? extends Image>>() {
|
||||
return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Cache<RegionAndName, ? extends Image>>(
|
||||
authException, seconds, new Supplier<Cache<RegionAndName, ? extends Image>>() {
|
||||
@Override
|
||||
public Map<RegionAndName, ? extends Image> get() {
|
||||
public Cache<RegionAndName, ? extends Image> get() {
|
||||
return supplier.get();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.aws.ec2.compute.config;
|
||||
|
||||
import static com.google.common.collect.Maps.newLinkedHashMap;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -47,7 +44,6 @@ import org.jclouds.compute.options.TemplateOptions;
|
|||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.ec2.compute.config.EC2ComputeServiceDependenciesModule;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.ec2.compute.domain.RegionNameAndIngressRules;
|
||||
import org.jclouds.ec2.compute.functions.CreateSecurityGroupIfNeeded;
|
||||
import org.jclouds.ec2.compute.functions.CreateUniqueKeyPair;
|
||||
import org.jclouds.ec2.compute.functions.CredentialsForInstance;
|
||||
|
@ -62,6 +58,9 @@ import org.jclouds.rest.internal.RestContextImpl;
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.Scopes;
|
||||
|
@ -80,15 +79,15 @@ public class AWSEC2ComputeServiceDependenciesModule extends EC2ComputeServiceDep
|
|||
bind(ComputeService.class).to(AWSEC2ComputeService.class);
|
||||
bind(new TypeLiteral<Function<RunningInstance, NodeMetadata>>() {
|
||||
}).to(RunningInstanceToNodeMetadata.class);
|
||||
bind(new TypeLiteral<Function<RunningInstance, Credentials>>() {
|
||||
bind(new TypeLiteral<CacheLoader<RunningInstance, Credentials>>() {
|
||||
}).to(CredentialsForInstance.class);
|
||||
bind(new TypeLiteral<Function<RegionNameAndIngressRules, String>>() {
|
||||
bind(new TypeLiteral<CacheLoader<RegionAndName, String>>() {
|
||||
}).to(CreateSecurityGroupIfNeeded.class);
|
||||
bind(new TypeLiteral<Function<RegionAndName, KeyPair>>() {
|
||||
bind(new TypeLiteral<CacheLoader<RegionAndName, KeyPair>>() {
|
||||
}).to(CreateUniqueKeyPair.class);
|
||||
bind(new TypeLiteral<Function<RegionNameAndPublicKeyMaterial, KeyPair>>() {
|
||||
}).to(ImportOrReturnExistingKeypair.class);
|
||||
bind(new TypeLiteral<Function<RegionAndName, Image>>() {
|
||||
bind(new TypeLiteral<CacheLoader<RegionAndName, Image>>() {
|
||||
}).to(RegionAndIdToImage.class);
|
||||
bind(new TypeLiteral<ComputeServiceContext>() {
|
||||
}).to(new TypeLiteral<ComputeServiceContextImpl<AWSEC2Client, AWSEC2AsyncClient>>() {
|
||||
|
@ -116,10 +115,8 @@ public class AWSEC2ComputeServiceDependenciesModule extends EC2ComputeServiceDep
|
|||
@Provides
|
||||
@Singleton
|
||||
@Named("PLACEMENT")
|
||||
protected Map<RegionAndName, String> placementGroupMap(CreateSecurityGroupIfNeeded in) {
|
||||
// doesn't seem to clear when someone issues remove(key)
|
||||
// return new MapMaker().makeComputingMap(in);
|
||||
return newLinkedHashMap();
|
||||
protected Cache<RegionAndName, String> placementGroupMap(CreateSecurityGroupIfNeeded in) {
|
||||
return CacheBuilder.newBuilder().build(in);
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.jclouds.ec2.domain.InstanceState;
|
|||
import org.jclouds.ec2.domain.RunningInstance;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.Cache;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
|
@ -47,9 +48,9 @@ public class AWSRunningInstanceToNodeMetadata extends RunningInstanceToNodeMetad
|
|||
|
||||
@Inject
|
||||
protected AWSRunningInstanceToNodeMetadata(Map<InstanceState, NodeState> instanceToNodeState,
|
||||
Map<String, Credentials> credentialStore, Map<RegionAndName, Image> instanceToImage,
|
||||
Map<String, Credentials> credentialStore, Supplier<Cache<RegionAndName, ? extends Image>> imageMap,
|
||||
@Memoized Supplier<Set<? extends Location>> locations, @Memoized Supplier<Set<? extends Hardware>> hardware) {
|
||||
super(instanceToNodeState, credentialStore, instanceToImage, locations, hardware);
|
||||
super(instanceToNodeState, credentialStore, imageMap, locations, hardware);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,6 +49,7 @@ import org.jclouds.logging.Logger;
|
|||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
|
@ -73,7 +74,7 @@ public class AWSEC2CreateNodesInGroupThenAddToSet extends EC2CreateNodesInGroupT
|
|||
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
|
||||
AWSEC2InstancePresent instancePresent,
|
||||
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
|
||||
Function<RunningInstance, Credentials> instanceToCredentials, Map<String, Credentials> credentialStore,
|
||||
Cache<RunningInstance, Credentials> instanceToCredentials, Map<String, Credentials> credentialStore,
|
||||
ComputeUtils utils, SpotInstanceRequestToAWSRunningInstance spotConverter) {
|
||||
super(client, templateBuilderProvider, createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, instancePresent,
|
||||
runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils);
|
||||
|
|
|
@ -37,7 +37,6 @@ import org.jclouds.compute.domain.Template;
|
|||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.ec2.compute.domain.RegionNameAndIngressRules;
|
||||
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
|
||||
import org.jclouds.ec2.compute.strategy.CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions;
|
||||
import org.jclouds.ec2.domain.KeyPair;
|
||||
|
@ -47,6 +46,7 @@ import org.jclouds.logging.Logger;
|
|||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.cache.Cache;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -59,21 +59,21 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions
|
|||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
@VisibleForTesting
|
||||
final Map<RegionAndName, String> placementGroupMap;
|
||||
final Cache<RegionAndName, String> placementGroupMap;
|
||||
@VisibleForTesting
|
||||
final CreatePlacementGroupIfNeeded createPlacementGroupIfNeeded;
|
||||
@VisibleForTesting
|
||||
final Function<RegionNameAndPublicKeyMaterial, KeyPair> importExistingKeyPair;
|
||||
|
||||
@Inject
|
||||
public CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions(
|
||||
Map<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") Map<RegionAndName, String> securityGroupMap,
|
||||
@Named("PLACEMENT") Map<RegionAndName, String> placementGroupMap,
|
||||
Function<RegionAndName, KeyPair> createUniqueKeyPair,
|
||||
Function<RegionNameAndIngressRules, String> createSecurityGroupIfNeeded,
|
||||
Provider<RunInstancesOptions> optionsProvider, CreatePlacementGroupIfNeeded createPlacementGroupIfNeeded,
|
||||
public CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions(Map<RegionAndName, KeyPair> knownKeys,
|
||||
Cache<RegionAndName, KeyPair> credentialsMap,
|
||||
@Named("SECURITY") Cache<RegionAndName, String> securityGroupMap,
|
||||
Provider<RunInstancesOptions> optionsProvider,
|
||||
@Named("PLACEMENT") Cache<RegionAndName, String> placementGroupMap,
|
||||
CreatePlacementGroupIfNeeded createPlacementGroupIfNeeded,
|
||||
Function<RegionNameAndPublicKeyMaterial, KeyPair> importExistingKeyPair) {
|
||||
super(credentialsMap, securityGroupMap, createUniqueKeyPair, createSecurityGroupIfNeeded, optionsProvider);
|
||||
super(knownKeys, credentialsMap, securityGroupMap, optionsProvider);
|
||||
this.placementGroupMap = placementGroupMap;
|
||||
this.createPlacementGroupIfNeeded = createPlacementGroupIfNeeded;
|
||||
this.importExistingKeyPair = importExistingKeyPair;
|
||||
|
@ -110,9 +110,8 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions
|
|||
// http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/index.html?using_cluster_computing.html
|
||||
placementGroupName = String.format("jclouds#%s#%s", group, region);
|
||||
RegionAndName regionAndName = new RegionAndName(region, placementGroupName);
|
||||
if (!placementGroupMap.containsKey(regionAndName)) {
|
||||
placementGroupMap.put(regionAndName, createPlacementGroupIfNeeded.apply(regionAndName));
|
||||
}
|
||||
// make this entry as needed
|
||||
placementGroupMap.getUnchecked(regionAndName);
|
||||
}
|
||||
return placementGroupName;
|
||||
}
|
||||
|
@ -120,7 +119,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions
|
|||
@Override
|
||||
protected String createOrImportKeyPair(String region, String group, TemplateOptions options) {
|
||||
RegionAndName key = new RegionAndName(region, "jclouds#" + group);
|
||||
KeyPair pair = credentialsMap.get(key);
|
||||
KeyPair pair = knownKeys.get(key);
|
||||
if (pair != null)
|
||||
return pair.getKeyName();
|
||||
if (and(hasPublicKeyMaterial, or(doesntNeedSshAfterImportingPublicKey, hasLoginCredential)).apply(options)) {
|
||||
|
@ -128,12 +127,12 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions
|
|||
options.dontAuthorizePublicKey();
|
||||
if (hasLoginCredential.apply(options))
|
||||
pair = pair.toBuilder().keyMaterial(options.getOverridingCredentials().credential).build();
|
||||
credentialsMap.put(key, pair);
|
||||
knownKeys.put(key, pair);
|
||||
} else {
|
||||
if (hasPublicKeyMaterial.apply(options)) {
|
||||
logger.warn("to avoid creating temporary keys in aws-ec2, use templateOption overrideLoginCredentialWith(id_rsa)");
|
||||
}
|
||||
return createUniqueKeyPairAndPutIntoMap(region, group);
|
||||
return super.createOrImportKeyPair(region, group, options);
|
||||
}
|
||||
return pair.getKeyName();
|
||||
}
|
||||
|
|
|
@ -47,6 +47,9 @@ import com.google.common.base.Function;
|
|||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
@ -58,12 +61,13 @@ import com.google.common.util.concurrent.Futures;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class AWSRegionAndNameToImageSupplier implements Supplier<Map<RegionAndName, ? extends Image>> {
|
||||
public class AWSRegionAndNameToImageSupplier implements Supplier<Cache<RegionAndName, ? extends Image>> {
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private final Map<RegionAndName, Image> images;
|
||||
private final Map<RegionAndName, Image> knownImages;
|
||||
private final CacheLoader<RegionAndName, Image> regionAndIdToImage;
|
||||
private final Set<String> clusterComputeIds;
|
||||
private final CallForImages.Factory factory;
|
||||
private final ExecutorService executor;
|
||||
|
@ -73,10 +77,11 @@ public class AWSRegionAndNameToImageSupplier implements Supplier<Map<RegionAndNa
|
|||
private final Iterable<String> clusterRegions;
|
||||
private final String ccAmiQuery;
|
||||
|
||||
|
||||
@Inject
|
||||
protected AWSRegionAndNameToImageSupplier(@Region Set<String> regions,
|
||||
@Named(PROPERTY_EC2_AMI_QUERY) String amiQuery, @Named(PROPERTY_EC2_CC_REGIONS) String clusterRegions,
|
||||
@Named(PROPERTY_EC2_CC_AMI_QUERY) String ccAmiQuery, Map<RegionAndName, Image> images,
|
||||
@Named(PROPERTY_EC2_CC_AMI_QUERY) String ccAmiQuery, Map<RegionAndName, Image> knownImages, CacheLoader<RegionAndName, Image> regionAndIdToImage,
|
||||
CallForImages.Factory factory, @ClusterCompute Set<String> clusterComputeIds,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
||||
this.factory = factory;
|
||||
|
@ -84,13 +89,14 @@ public class AWSRegionAndNameToImageSupplier implements Supplier<Map<RegionAndNa
|
|||
this.amiQuery = amiQuery;
|
||||
this.clusterRegions = Splitter.on(',').split(clusterRegions);
|
||||
this.ccAmiQuery = ccAmiQuery;
|
||||
this.images = images;
|
||||
this.knownImages = knownImages;
|
||||
this.regionAndIdToImage=regionAndIdToImage;
|
||||
this.clusterComputeIds = clusterComputeIds;
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<RegionAndName, ? extends Image> get() {
|
||||
public Cache<RegionAndName, ? extends Image> get() {
|
||||
Future<Iterable<Image>> normalImages = images(regions, amiQuery, PROPERTY_EC2_AMI_QUERY);
|
||||
ImmutableSet<Image> clusterImages;
|
||||
try {
|
||||
|
@ -115,8 +121,8 @@ public class AWSRegionAndNameToImageSupplier implements Supplier<Map<RegionAndNa
|
|||
Throwables.propagate(e);
|
||||
return null;
|
||||
}
|
||||
|
||||
images.putAll(uniqueIndex(parsedImages, new Function<Image, RegionAndName>() {
|
||||
knownImages.clear();
|
||||
knownImages.putAll(uniqueIndex(parsedImages, new Function<Image, RegionAndName>() {
|
||||
|
||||
@Override
|
||||
public RegionAndName apply(Image from) {
|
||||
|
@ -124,7 +130,13 @@ public class AWSRegionAndNameToImageSupplier implements Supplier<Map<RegionAndNa
|
|||
}
|
||||
|
||||
}));
|
||||
return images;
|
||||
logger.debug("<< images(%d)", knownImages.size());
|
||||
Cache<RegionAndName, Image> cache = CacheBuilder.newBuilder().build(regionAndIdToImage);
|
||||
// seed the cache
|
||||
for (RegionAndName image : knownImages.keySet()){
|
||||
cache.getUnchecked(image);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
private Future<Iterable<Image>> images(Iterable<String> regions, String query, String tag) {
|
||||
|
|
|
@ -88,7 +88,7 @@ public class AWSEC2TemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest {
|
|||
.build();
|
||||
|
||||
assert (template.getImage().getProviderId().startsWith("ami-")) : template;
|
||||
assertEquals(template.getImage().getOperatingSystem().getVersion(), "11.10");
|
||||
assertEquals(template.getImage().getOperatingSystem().getVersion(), "11.04");
|
||||
assertEquals(template.getImage().getOperatingSystem().is64Bit(), false);
|
||||
assertEquals(template.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU);
|
||||
assertEquals(template.getImage().getUserMetadata().get("rootDeviceType"), "instance-store");
|
||||
|
@ -107,7 +107,7 @@ public class AWSEC2TemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest {
|
|||
.build();
|
||||
|
||||
assert (template.getImage().getProviderId().startsWith("ami-")) : template;
|
||||
assertEquals(template.getImage().getOperatingSystem().getVersion(), "11.10");
|
||||
assertEquals(template.getImage().getOperatingSystem().getVersion(), "11.04");
|
||||
assertEquals(template.getImage().getOperatingSystem().is64Bit(), false);
|
||||
assertEquals(template.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU);
|
||||
assertEquals(template.getImage().getUserMetadata().get("rootDeviceType"), "instance-store");
|
||||
|
@ -183,7 +183,7 @@ public class AWSEC2TemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest {
|
|||
fastestTemplate = context.getComputeService().templateBuilder().fastest().build();
|
||||
assert (fastestTemplate.getImage().getProviderId().startsWith("ami-")) : fastestTemplate;
|
||||
assertEquals(fastestTemplate.getHardware().getProviderId(), InstanceType.CC1_4XLARGE);
|
||||
assertEquals(fastestTemplate.getImage().getOperatingSystem().getVersion(), "11.10");
|
||||
assertEquals(fastestTemplate.getImage().getOperatingSystem().getVersion(), "11.04");
|
||||
assertEquals(fastestTemplate.getImage().getOperatingSystem().is64Bit(), true);
|
||||
assertEquals(fastestTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU);
|
||||
assertEquals(fastestTemplate.getImage().getUserMetadata().get("rootDeviceType"), "ebs");
|
||||
|
|
|
@ -45,6 +45,10 @@ import org.testng.annotations.Test;
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
@ -118,7 +122,7 @@ public class AWSRunningInstanceToNodeMetadataTest {
|
|||
Map<String, Credentials> credentialStore) {
|
||||
Map<InstanceState, NodeState> instanceToNodeState = EC2ComputeServiceDependenciesModule.instanceToNodeState;
|
||||
|
||||
Map<RegionAndName, Image> instanceToImage = Maps.uniqueIndex(images, new Function<Image, RegionAndName>() {
|
||||
final ImmutableMap<RegionAndName, Image> backing = Maps.uniqueIndex(images, new Function<Image, RegionAndName>() {
|
||||
|
||||
@Override
|
||||
public RegionAndName apply(Image from) {
|
||||
|
@ -127,12 +131,22 @@ public class AWSRunningInstanceToNodeMetadataTest {
|
|||
|
||||
});
|
||||
|
||||
Cache<RegionAndName, Image> instanceToImage = CacheBuilder.newBuilder().build(new CacheLoader<RegionAndName, Image> (){
|
||||
|
||||
@Override
|
||||
public Image load(RegionAndName key) throws Exception {
|
||||
return backing.get(key);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
return createNodeParser(hardware, locations, credentialStore, instanceToNodeState, instanceToImage);
|
||||
}
|
||||
|
||||
private AWSRunningInstanceToNodeMetadata createNodeParser(final ImmutableSet<Hardware> hardware,
|
||||
final ImmutableSet<Location> locations, Map<String, Credentials> credentialStore,
|
||||
Map<InstanceState, NodeState> instanceToNodeState, Map<RegionAndName, Image> instanceToImage) {
|
||||
Map<InstanceState, NodeState> instanceToNodeState, Cache<RegionAndName, ? extends Image> instanceToImage) {
|
||||
Supplier<Set<? extends Location>> locationSupplier = new Supplier<Set<? extends Location>>() {
|
||||
|
||||
@Override
|
||||
|
@ -150,7 +164,8 @@ public class AWSRunningInstanceToNodeMetadataTest {
|
|||
|
||||
};
|
||||
AWSRunningInstanceToNodeMetadata parser = new AWSRunningInstanceToNodeMetadata(instanceToNodeState,
|
||||
credentialStore, instanceToImage, locationSupplier, hardwareSupplier);
|
||||
credentialStore, Suppliers.<Cache<RegionAndName, ? extends Image>> ofInstance(instanceToImage),
|
||||
locationSupplier, hardwareSupplier);
|
||||
return parser;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,13 +54,14 @@ import org.jclouds.scriptbuilder.domain.Statements;
|
|||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit")
|
||||
@Test(groups = "unit", singleThreaded = true, testName = "CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsTest")
|
||||
public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
||||
private static final Provider<RunInstancesOptions> OPTIONS_PROVIDER = new javax.inject.Provider<RunInstancesOptions>() {
|
||||
|
||||
|
@ -385,7 +386,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
}
|
||||
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_reusesKeyWhenToldToWithRunScriptButNoCredentials() {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
|
@ -401,7 +402,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
|
||||
expect(options.getOverridingCredentials()).andReturn(null);
|
||||
expect(options.getRunScript()).andReturn(Statements.exec("echo foo"));
|
||||
expect(strategy.credentialsMap.containsKey(new RegionAndName(region, userSuppliedKeyPair))).andReturn(false);
|
||||
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, userSuppliedKeyPair))).andThrow(new NullPointerException());
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
|
@ -432,7 +433,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
|
||||
expect(options.getOverridingCredentials()).andReturn(null);
|
||||
expect(options.getRunScript()).andReturn(Statements.exec("echo foo"));
|
||||
expect(strategy.credentialsMap.containsKey(new RegionAndName(region, userSuppliedKeyPair))).andReturn(true);
|
||||
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, userSuppliedKeyPair))).andReturn(keyPair);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
|
@ -463,11 +464,13 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
|
||||
expect(options.getOverridingCredentials()).andReturn(new Credentials(null, "MyRsa")).atLeastOnce();
|
||||
expect(
|
||||
strategy.credentialsMap.put(new RegionAndName(region, userSuppliedKeyPair), KeyPair.builder()
|
||||
.region(region).keyName(userSuppliedKeyPair).keyFingerprint("//TODO").keyMaterial("MyRsa").build()))
|
||||
.andReturn(null);
|
||||
strategy.knownKeys.put(
|
||||
new RegionAndName(region, tag),
|
||||
KeyPair.builder().region(region).keyName(userSuppliedKeyPair).keyFingerprint("//TODO")
|
||||
.keyMaterial("MyRsa").build())).andReturn(null);
|
||||
strategy.credentialsMap.invalidate(new RegionAndName(region, tag));
|
||||
expect(options.getRunScript()).andReturn(Statements.exec("echo foo"));
|
||||
expect(strategy.credentialsMap.containsKey(new RegionAndName(region, userSuppliedKeyPair))).andReturn(true);
|
||||
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, userSuppliedKeyPair))).andReturn(keyPair);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
|
@ -483,6 +486,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
verifyStrategy(strategy);
|
||||
}
|
||||
|
||||
@Test(enabled = false)
|
||||
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_importsKeyPairAndUnsetsTemplateInstructionWhenPublicKeySuppliedAndAddsCredentialToMapWhenOverridingCredsAreSet() {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
|
@ -496,18 +500,19 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
KeyPair keyPair = new KeyPair(region, "jclouds#" + group, "fingerprint", null);
|
||||
|
||||
// setup expectations
|
||||
expect(strategy.knownKeys.get(new RegionAndName(region, "jclouds#" + group))).andReturn(null);
|
||||
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
|
||||
expect(options.shouldAutomaticallyCreateKeyPair()).andReturn(shouldAutomaticallyCreateKeyPair);
|
||||
expect(strategy.credentialsMap.get(new RegionAndName(region, "jclouds#" + group))).andReturn(null);
|
||||
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, "jclouds#" + group))).andThrow(new NullPointerException());
|
||||
expect(options.getPublicKey()).andReturn("ssh-rsa").times(2);
|
||||
expect(strategy.importExistingKeyPair.apply(new RegionNameAndPublicKeyMaterial(region, group, "ssh-rsa")))
|
||||
.andReturn(keyPair);
|
||||
expect(options.dontAuthorizePublicKey()).andReturn(options);
|
||||
expect(options.getOverridingCredentials()).andReturn(new Credentials("foo", "bar")).times(3);
|
||||
expect(options.getRunScript()).andReturn(null).times(2);
|
||||
expect(options.getPrivateKey()).andReturn(null);
|
||||
expect(options.dontAuthorizePublicKey()).andReturn(options);
|
||||
expect(
|
||||
strategy.credentialsMap.put(new RegionAndName(region, "jclouds#" + group),
|
||||
strategy.knownKeys.put(new RegionAndName(region, "jclouds#" + group),
|
||||
keyPair.toBuilder().keyMaterial("bar").build())).andReturn(null);
|
||||
|
||||
// replay mocks
|
||||
|
@ -522,6 +527,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
verifyStrategy(strategy);
|
||||
}
|
||||
|
||||
@Test(enabled = false)
|
||||
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_importsKeyPairAndUnsetsTemplateInstructionWhenPublicKeySupplied() {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
|
@ -535,9 +541,10 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
KeyPair keyPair = new KeyPair(region, "jclouds#" + group, "fingerprint", null);
|
||||
|
||||
// setup expectations
|
||||
expect(strategy.knownKeys.get(new RegionAndName(region, "jclouds#" + group))).andReturn(null);
|
||||
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
|
||||
expect(options.shouldAutomaticallyCreateKeyPair()).andReturn(shouldAutomaticallyCreateKeyPair);
|
||||
expect(strategy.credentialsMap.get(new RegionAndName(region, "jclouds#" + group))).andReturn(null);
|
||||
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, "jclouds#" + group))).andThrow(new NullPointerException());
|
||||
expect(options.getPublicKey()).andReturn("ssh-rsa").times(2);
|
||||
expect(strategy.importExistingKeyPair.apply(new RegionNameAndPublicKeyMaterial(region, group, "ssh-rsa")))
|
||||
.andReturn(keyPair);
|
||||
|
@ -545,7 +552,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
expect(options.getOverridingCredentials()).andReturn(null);
|
||||
expect(options.getRunScript()).andReturn(null).times(2);
|
||||
expect(options.getPrivateKey()).andReturn(null);
|
||||
expect(strategy.credentialsMap.put(new RegionAndName(region, "jclouds#" + group), keyPair)).andReturn(null);
|
||||
expect(strategy.knownKeys.put(new RegionAndName(region, "jclouds#" + group), keyPair)).andReturn(null);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
|
@ -573,16 +580,13 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
KeyPair keyPair = createMock(KeyPair.class);
|
||||
|
||||
// setup expectations
|
||||
expect(strategy.knownKeys.get(new RegionAndName(region, "jclouds#" + group))).andReturn(null);
|
||||
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
|
||||
expect(options.shouldAutomaticallyCreateKeyPair()).andReturn(shouldAutomaticallyCreateKeyPair);
|
||||
expect(strategy.credentialsMap.get(new RegionAndName(region, "jclouds#" + group))).andReturn(null);
|
||||
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, group))).andReturn(keyPair);
|
||||
expect(options.getPublicKey()).andReturn(null).times(2);
|
||||
expect(strategy.createUniqueKeyPair.apply(new RegionAndName(region, group))).andReturn(keyPair);
|
||||
expect(keyPair.getRegion()).andReturn(region).atLeastOnce();
|
||||
expect(keyPair.getKeyName()).andReturn(systemGeneratedKeyPairName).atLeastOnce();
|
||||
expect(options.getRunScript()).andReturn(null);
|
||||
expect(strategy.credentialsMap.put(new RegionAndName(region, systemGeneratedKeyPairName), keyPair)).andReturn(
|
||||
null);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
|
@ -613,10 +617,10 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
KeyPair keyPair = createMock(KeyPair.class);
|
||||
|
||||
// setup expectations
|
||||
expect(strategy.knownKeys.get(new RegionAndName(region, "jclouds#" + group))).andReturn(keyPair);
|
||||
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
|
||||
expect(options.getRunScript()).andReturn(null);
|
||||
expect(options.shouldAutomaticallyCreateKeyPair()).andReturn(shouldAutomaticallyCreateKeyPair);
|
||||
expect(strategy.credentialsMap.get(new RegionAndName(region, "jclouds#" + group))).andReturn(keyPair);
|
||||
expect(keyPair.getKeyName()).andReturn(systemGeneratedKeyPairName).atLeastOnce();
|
||||
// replay mocks
|
||||
replay(options);
|
||||
|
@ -673,7 +677,6 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
Set<String> groupNames = ImmutableSet.<String> of();
|
||||
int[] ports = new int[] {};
|
||||
boolean shouldAuthorizeSelf = true;
|
||||
boolean groupExisted = false;
|
||||
Set<String> returnVal = ImmutableSet.<String> of(generatedMarkerGroup);
|
||||
|
||||
// create mocks
|
||||
|
@ -686,9 +689,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
expect(options.getInboundPorts()).andReturn(ports).atLeastOnce();
|
||||
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
|
||||
ports, shouldAuthorizeSelf);
|
||||
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(groupExisted);
|
||||
expect(strategy.createSecurityGroupIfNeeded.apply(regionNameAndIngressRules)).andReturn(generatedMarkerGroup);
|
||||
expect(strategy.securityGroupMap.put(regionNameAndIngressRules, generatedMarkerGroup)).andReturn(null);
|
||||
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(group);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
|
@ -710,7 +711,6 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
Set<String> groupNames = ImmutableSet.<String> of();
|
||||
int[] ports = new int[] { 22, 80 };
|
||||
boolean shouldAuthorizeSelf = true;
|
||||
boolean groupExisted = false;
|
||||
Set<String> returnVal = ImmutableSet.<String> of(generatedMarkerGroup);
|
||||
|
||||
// create mocks
|
||||
|
@ -723,9 +723,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
expect(options.getInboundPorts()).andReturn(ports).atLeastOnce();
|
||||
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
|
||||
ports, shouldAuthorizeSelf);
|
||||
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(groupExisted);
|
||||
expect(strategy.createSecurityGroupIfNeeded.apply(regionNameAndIngressRules)).andReturn(generatedMarkerGroup);
|
||||
expect(strategy.securityGroupMap.put(regionNameAndIngressRules, generatedMarkerGroup)).andReturn(null);
|
||||
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(generatedMarkerGroup);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
|
@ -747,7 +745,6 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
Set<String> groupNames = ImmutableSet.<String> of();
|
||||
int[] ports = new int[] {};
|
||||
boolean shouldAuthorizeSelf = true;
|
||||
boolean groupExisted = true;
|
||||
Set<String> returnVal = ImmutableSet.<String> of(generatedMarkerGroup);
|
||||
|
||||
// create mocks
|
||||
|
@ -760,7 +757,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
expect(options.getInboundPorts()).andReturn(ports).atLeastOnce();
|
||||
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
|
||||
ports, shouldAuthorizeSelf);
|
||||
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(groupExisted);
|
||||
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(generatedMarkerGroup);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
|
@ -793,13 +790,9 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
expect(options.getGroupIds()).andReturn(ImmutableSet.<String>of());
|
||||
expect(options.getGroups()).andReturn(groupNames).atLeastOnce();
|
||||
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
|
||||
ports, shouldAuthorizeSelf); // note
|
||||
// this
|
||||
// works
|
||||
// since
|
||||
// there's
|
||||
// no equals on portsq
|
||||
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(groupExisted);
|
||||
ports, shouldAuthorizeSelf);
|
||||
|
||||
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(groupExisted ? "tag" : null);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
|
@ -832,13 +825,9 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
expect(options.getGroupIds()).andReturn(ImmutableSet.<String>of("group1", "group2"));
|
||||
expect(options.getGroups()).andReturn(groupNames).atLeastOnce();
|
||||
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
|
||||
ports, shouldAuthorizeSelf); // note
|
||||
// this
|
||||
// works
|
||||
// since
|
||||
// there's
|
||||
// no equals on portsq
|
||||
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(groupExisted);
|
||||
ports, shouldAuthorizeSelf);
|
||||
|
||||
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(groupExisted ? "tag" : null);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
|
@ -895,11 +884,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
// setup expectations
|
||||
expect(options.getPlacementGroup()).andReturn(userSuppliedPlacementGroup);
|
||||
expect(options.shouldAutomaticallyCreatePlacementGroup()).andReturn(shouldAutomaticallyCreatePlacementGroup);
|
||||
expect(strategy.placementGroupMap.containsKey(new RegionAndName(region, generatedMarkerGroup))).andReturn(false);
|
||||
expect(strategy.createPlacementGroupIfNeeded.apply(new RegionAndName(region, generatedMarkerGroup))).andReturn(
|
||||
generatedMarkerGroup);
|
||||
expect(strategy.placementGroupMap.put(new RegionAndName(region, generatedMarkerGroup), generatedMarkerGroup))
|
||||
.andReturn(null);
|
||||
expect(strategy.placementGroupMap.getUnchecked(new RegionAndName(region, generatedMarkerGroup))).andReturn(generatedMarkerGroup);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
|
@ -946,37 +931,33 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
}
|
||||
|
||||
private void verifyStrategy(CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions strategy) {
|
||||
verify(strategy.knownKeys);
|
||||
verify(strategy.credentialsMap);
|
||||
verify(strategy.securityGroupMap);
|
||||
verify(strategy.placementGroupMap);
|
||||
verify(strategy.createUniqueKeyPair);
|
||||
verify(strategy.importExistingKeyPair);
|
||||
verify(strategy.createSecurityGroupIfNeeded);
|
||||
verify(strategy.createPlacementGroupIfNeeded);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions setupStrategy() {
|
||||
Map<RegionAndName, KeyPair> credentialsMap = createMock(Map.class);
|
||||
Map<RegionAndName, String> securityGroupMap = createMock(Map.class);
|
||||
Map<RegionAndName, String> placementGroupMap = createMock(Map.class);
|
||||
Function<RegionAndName, KeyPair> createOrGetKeyPair = createMock(Function.class);
|
||||
Function<RegionNameAndIngressRules, String> createSecurityGroupIfNeeded = createMock(Function.class);
|
||||
Map<RegionAndName, KeyPair> knownKeys = createMock(Map.class);
|
||||
Cache<RegionAndName, KeyPair> credentialsMap = createMock(Cache.class);
|
||||
Cache<RegionAndName, String> securityGroupMap = createMock(Cache.class);
|
||||
Cache<RegionAndName, String> placementGroupMap = createMock(Cache.class);
|
||||
Function<RegionNameAndPublicKeyMaterial, KeyPair> importExistingKeyPair = createMock(Function.class);
|
||||
CreatePlacementGroupIfNeeded createPlacementGroupIfNeeded = createMock(CreatePlacementGroupIfNeeded.class);
|
||||
|
||||
return new CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions(credentialsMap, securityGroupMap,
|
||||
placementGroupMap, createOrGetKeyPair, createSecurityGroupIfNeeded, OPTIONS_PROVIDER,
|
||||
createPlacementGroupIfNeeded, importExistingKeyPair);
|
||||
return new CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions(knownKeys, credentialsMap, securityGroupMap,
|
||||
OPTIONS_PROVIDER, placementGroupMap, createPlacementGroupIfNeeded, importExistingKeyPair);
|
||||
}
|
||||
|
||||
private void replayStrategy(CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions strategy) {
|
||||
replay(strategy.knownKeys);
|
||||
replay(strategy.credentialsMap);
|
||||
replay(strategy.securityGroupMap);
|
||||
replay(strategy.placementGroupMap);
|
||||
replay(strategy.createUniqueKeyPair);
|
||||
replay(strategy.importExistingKeyPair);
|
||||
replay(strategy.createSecurityGroupIfNeeded);
|
||||
replay(strategy.createPlacementGroupIfNeeded);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,10 +25,14 @@ import java.net.URI;
|
|||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.aws.domain.Region;
|
||||
import org.jclouds.aws.ec2.config.AWSEC2RestClientModule;
|
||||
import org.jclouds.aws.filters.FormSigner;
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.date.DateService;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.RequiresHttp;
|
||||
import org.jclouds.rest.ConfiguresRestClient;
|
||||
|
@ -38,8 +42,12 @@ import org.jclouds.rest.RestContextSpec;
|
|||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.Provides;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
|
@ -60,6 +68,18 @@ public abstract class BaseAWSEC2AsyncClientTest<T> extends RestClientTest<T> {
|
|||
bindRegionsToProvider(Regions.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
Cache<RegionAndName, Image> provide(){
|
||||
return CacheBuilder.newBuilder().build(new CacheLoader<RegionAndName, Image>() {
|
||||
|
||||
@Override
|
||||
public Image load(RegionAndName key) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
static class Regions implements javax.inject.Provider<Map<String, URI>> {
|
||||
@Override
|
||||
public Map<String, URI> get() {
|
||||
|
|
|
@ -32,7 +32,6 @@ import javax.inject.Named;
|
|||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.Constants;
|
||||
import org.jclouds.cloudsigma.CloudSigmaAsyncClient;
|
||||
import org.jclouds.cloudsigma.CloudSigmaClient;
|
||||
import org.jclouds.cloudsigma.domain.Device;
|
||||
import org.jclouds.cloudsigma.domain.DriveInfo;
|
||||
|
@ -60,33 +59,35 @@ import org.jclouds.logging.Logger;
|
|||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSet.Builder;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
|
||||
/**
|
||||
* defines the connection between the {@link CloudSigmaClient} implementation and the jclouds
|
||||
* {@link ComputeService}
|
||||
* defines the connection between the {@link CloudSigmaClient} implementation
|
||||
* and the jclouds {@link ComputeService}
|
||||
*
|
||||
*/
|
||||
@Singleton
|
||||
public class CloudSigmaComputeServiceAdapter implements
|
||||
ComputeServiceAdapter<ServerInfo, Hardware, DriveInfo, Location> {
|
||||
ComputeServiceAdapter<ServerInfo, Hardware, DriveInfo, Location> {
|
||||
private static final Predicate<DriveInfo> PREINSTALLED_DISK = Predicates.and(Predicates.notNull(),
|
||||
new Predicate<DriveInfo>() {
|
||||
new Predicate<DriveInfo>() {
|
||||
|
||||
@Override
|
||||
public boolean apply(DriveInfo drive) {
|
||||
return drive.getType().equals(DriveType.DISK) && drive.getDriveType().contains("preinstalled");
|
||||
}
|
||||
@Override
|
||||
public boolean apply(DriveInfo drive) {
|
||||
return drive.getType().equals(DriveType.DISK) && drive.getDriveType().contains("preinstalled");
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
private final CloudSigmaClient client;
|
||||
private final CloudSigmaAsyncClient aclient;
|
||||
private final Predicate<DriveInfo> driveNotClaimed;
|
||||
private final JustProvider locationSupplier;
|
||||
private final String defaultVncPassword;
|
||||
private final Map<String, DriveInfo> cache;
|
||||
private final Cache<String, DriveInfo> cache;
|
||||
private final ExecutorService executor;
|
||||
|
||||
@Resource
|
||||
|
@ -94,12 +95,10 @@ public class CloudSigmaComputeServiceAdapter implements
|
|||
protected Logger logger = Logger.NULL;
|
||||
|
||||
@Inject
|
||||
public CloudSigmaComputeServiceAdapter(CloudSigmaClient client, CloudSigmaAsyncClient aclient,
|
||||
Predicate<DriveInfo> driveNotClaimed, JustProvider locationSupplier,
|
||||
@Named(CloudSigmaConstants.PROPERTY_VNC_PASSWORD) String defaultVncPassword, Map<String, DriveInfo> cache,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
||||
public CloudSigmaComputeServiceAdapter(CloudSigmaClient client, Predicate<DriveInfo> driveNotClaimed,
|
||||
JustProvider locationSupplier, @Named(CloudSigmaConstants.PROPERTY_VNC_PASSWORD) String defaultVncPassword,
|
||||
Cache<String, DriveInfo> cache, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
||||
this.client = checkNotNull(client, "client");
|
||||
this.aclient = checkNotNull(aclient, "aclient");
|
||||
this.driveNotClaimed = checkNotNull(driveNotClaimed, "driveNotClaimed");
|
||||
this.locationSupplier = checkNotNull(locationSupplier, "locationSupplier");
|
||||
this.defaultVncPassword = checkNotNull(defaultVncPassword, "defaultVncPassword");
|
||||
|
@ -109,21 +108,20 @@ public class CloudSigmaComputeServiceAdapter implements
|
|||
|
||||
@Override
|
||||
public ServerInfo createNodeWithGroupEncodedIntoNameThenStoreCredentials(String tag, String name, Template template,
|
||||
Map<String, Credentials> credentialStore) {
|
||||
Map<String, Credentials> credentialStore) {
|
||||
long bootSize = (long) (template.getHardware().getVolumes().get(0).getSize() * 1024 * 1024 * 1024l);
|
||||
logger.debug(">> imaging boot drive source(%s) bytes(%d)", template.getImage().getId(), bootSize);
|
||||
DriveInfo drive = client.cloneDrive(template.getImage().getId(), template.getImage().getId(),
|
||||
new CloneDriveOptions().size(bootSize));
|
||||
new CloneDriveOptions().size(bootSize));
|
||||
boolean success = driveNotClaimed.apply(drive);
|
||||
logger.debug("<< image(%s) complete(%s)", drive.getUuid(), success);
|
||||
if (!success) {
|
||||
client.destroyDrive(drive.getUuid());
|
||||
throw new IllegalStateException("could not image drive in time!");
|
||||
}
|
||||
cache.put(drive.getUuid(), drive);
|
||||
|
||||
Server toCreate = Servers.small(name, drive.getUuid(), defaultVncPassword).mem(template.getHardware().getRam())
|
||||
.cpu((int) (template.getHardware().getProcessors().get(0).getSpeed())).build();
|
||||
.cpu((int) (template.getHardware().getProcessors().get(0).getSpeed())).build();
|
||||
|
||||
logger.debug(">> creating server");
|
||||
ServerInfo from = client.createServer(toCreate);
|
||||
|
@ -131,7 +129,7 @@ public class CloudSigmaComputeServiceAdapter implements
|
|||
logger.debug(">> starting server(%s)", from.getUuid());
|
||||
client.startServer(from.getUuid());
|
||||
// store the credentials so that later functions can use them
|
||||
credentialStore.put("node#"+ from.getUuid(), new Credentials("cloudsigma", "cloudsigma"));
|
||||
credentialStore.put("node#" + from.getUuid(), new Credentials("root", defaultVncPassword));
|
||||
return from;
|
||||
}
|
||||
|
||||
|
@ -155,30 +153,39 @@ public class CloudSigmaComputeServiceAdapter implements
|
|||
return "sizeLessThanOrEqual(" + size + ")";
|
||||
}
|
||||
|
||||
}).ids(id).ram(ram).processors(ImmutableList.of(new Processor(1, cpu))).volumes(
|
||||
ImmutableList.<Volume> of(new VolumeImpl(size, true, true))).build());
|
||||
}).ids(id).ram(ram).processors(ImmutableList.of(new Processor(1, cpu)))
|
||||
.volumes(ImmutableList.<Volume> of(new VolumeImpl(size, true, true))).build());
|
||||
}
|
||||
return hardware.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* look up the current standard images and do not error out, if they are not found.
|
||||
* look up the current standard images and do not error out, if they are not
|
||||
* found.
|
||||
*/
|
||||
@Override
|
||||
public Iterable<DriveInfo> listImages() {
|
||||
Iterable<DriveInfo> drives = transformParallel(client.listStandardDrives(),
|
||||
new Function<String, Future<DriveInfo>>() {
|
||||
new Function<String, Future<DriveInfo>>() {
|
||||
|
||||
@Override
|
||||
public Future<DriveInfo> apply(String input) {
|
||||
return aclient.getDriveInfo(input);
|
||||
@Override
|
||||
public Future<DriveInfo> apply(String input) {
|
||||
try {
|
||||
return Futures.immediateFuture(cache.getUnchecked(input));
|
||||
} catch (NullPointerException e) {
|
||||
logger.debug("drive %s not found", input);
|
||||
} catch (UncheckedExecutionException e) {
|
||||
logger.warn(e, "error finding drive %s: %s", input, e.getMessage());
|
||||
}
|
||||
return Futures.immediateFuture(null);
|
||||
}
|
||||
|
||||
}, executor, null, logger, "drives");
|
||||
Iterable<DriveInfo> returnVal = filter(drives, PREINSTALLED_DISK);
|
||||
for (DriveInfo drive : returnVal)
|
||||
cache.put(drive.getUuid(), drive);
|
||||
return returnVal;
|
||||
@Override
|
||||
public String toString() {
|
||||
return "seedDriveCache()";
|
||||
}
|
||||
}, executor, null, logger, "drives");
|
||||
return filter(drives, PREINSTALLED_DISK);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
|
@ -45,13 +46,16 @@ import org.jclouds.compute.domain.Volume;
|
|||
import org.jclouds.compute.domain.VolumeBuilder;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.logging.Logger;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
|
@ -113,10 +117,13 @@ public class ServerInfoToNodeMetadata implements Function<ServerInfo, NodeMetada
|
|||
|
||||
@Singleton
|
||||
public static final class DeviceToVolume implements Function<Device, Volume> {
|
||||
private final Map<String, DriveInfo> cache;
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private final Cache<String, DriveInfo> cache;
|
||||
|
||||
@Inject
|
||||
public DeviceToVolume(Map<String, DriveInfo> cache) {
|
||||
public DeviceToVolume(Cache<String, DriveInfo> cache) {
|
||||
this.cache = checkNotNull(cache, "cache");
|
||||
}
|
||||
|
||||
|
@ -124,9 +131,13 @@ public class ServerInfoToNodeMetadata implements Function<ServerInfo, NodeMetada
|
|||
public Volume apply(Device input) {
|
||||
VolumeBuilder builder = new VolumeBuilder();
|
||||
builder.id(input.getId());
|
||||
DriveInfo drive = cache.get(input.getDriveUuid());
|
||||
if (drive != null) {
|
||||
try {
|
||||
DriveInfo drive = cache.getUnchecked(input.getDriveUuid());
|
||||
builder.size(drive.getSize() / 1024 / 1024f);
|
||||
} catch (NullPointerException e) {
|
||||
logger.debug("drive %s not found", input.getDriveUuid());
|
||||
} catch (UncheckedExecutionException e) {
|
||||
logger.warn(e, "error finding drive %s: %s", input.getDriveUuid(), e.getMessage());
|
||||
}
|
||||
return new VolumeBuilder().durable(true).type(Volume.Type.NAS).build();
|
||||
}
|
||||
|
@ -141,10 +152,13 @@ public class ServerInfoToNodeMetadata implements Function<ServerInfo, NodeMetada
|
|||
*/
|
||||
@Singleton
|
||||
public static class GetImageIdFromServer implements Function<Server, String> {
|
||||
private final Map<String, DriveInfo> cache;
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private final Cache<String, DriveInfo> cache;
|
||||
|
||||
@Inject
|
||||
public GetImageIdFromServer(Map<String, DriveInfo> cache) {
|
||||
public GetImageIdFromServer(Cache<String, DriveInfo> cache) {
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
|
@ -155,9 +169,12 @@ public class ServerInfoToNodeMetadata implements Function<ServerInfo, NodeMetada
|
|||
Device bootDevice = from.getDevices().get(bootDeviceId);
|
||||
if (bootDevice != null) {
|
||||
try {
|
||||
imageId = cache.get(bootDevice.getDriveUuid()).getName();
|
||||
DriveInfo drive = cache.getUnchecked(bootDevice.getDriveUuid());
|
||||
imageId = drive.getName();
|
||||
} catch (NullPointerException e) {
|
||||
|
||||
logger.debug("drive %s not found", bootDevice.getDriveUuid());
|
||||
} catch (UncheckedExecutionException e) {
|
||||
logger.warn(e, "error finding drive %s: %s", bootDevice.getDriveUuid(), e.getMessage());
|
||||
}
|
||||
}
|
||||
return imageId;
|
||||
|
|
Loading…
Reference in New Issue