Merge branch 'master' of git://github.com/jclouds/jclouds into large-blob

This commit is contained in:
Tibor Kiss 2011-03-10 12:14:17 +01:00
commit beb915424b
70 changed files with 4952 additions and 335 deletions

View File

@ -21,6 +21,7 @@ package org.jclouds.ec2.binders;
import static com.google.common.base.Preconditions.checkArgument;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.http.HttpRequest;
@ -34,11 +35,22 @@ import org.jclouds.rest.Binder;
*/
@Singleton
public class IfNotNullBindAvailabilityZoneToFormParam implements Binder {
private final String param;
@Inject
protected IfNotNullBindAvailabilityZoneToFormParam() {
this("Placement.AvailabilityZone");
}
protected IfNotNullBindAvailabilityZoneToFormParam(String param) {
this.param = param;
}
@Override
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
if (input != null) {
checkArgument(input instanceof String, "this binder is only valid for AvailabilityZone!");
return ModifyRequest.addFormParam(request, "Placement.AvailabilityZone", (String) input);
checkArgument(input instanceof String, "this binder is only valid for String!");
return ModifyRequest.addFormParam(request, param, (String) input);
}
return request;
}

View File

@ -66,8 +66,8 @@ 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.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableMultimap.Builder;
import com.google.common.collect.ImmutableSet;
/**
@ -177,12 +177,12 @@ public class EC2ComputeService extends BaseComputeService {
@Override
public Set<? extends NodeMetadata> destroyNodesMatching(Predicate<NodeMetadata> filter) {
Set<? extends NodeMetadata> deadOnes = super.destroyNodesMatching(filter);
Builder<String, String> regionGroups = ImmutableMap.<String, String> builder();
Builder<String, String> regionGroups = ImmutableMultimap.<String, String> builder();
for (NodeMetadata nodeMetadata : deadOnes) {
if (nodeMetadata.getGroup() != null)
regionGroups.put(AWSUtils.parseHandle(nodeMetadata.getId())[0], nodeMetadata.getGroup());
}
for (Entry<String, String> regionGroup : regionGroups.build().entrySet()) {
for (Entry<String, String> regionGroup : regionGroups.build().entries()) {
cleanUpIncidentalResources(regionGroup);
}
return deadOnes;

View File

@ -25,7 +25,6 @@ import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_AMI_OWNERS;
import java.security.SecureRandom;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.inject.Named;
import javax.inject.Singleton;
@ -54,13 +53,10 @@ import org.jclouds.ec2.compute.options.EC2TemplateOptions;
import org.jclouds.ec2.domain.InstanceState;
import org.jclouds.ec2.domain.KeyPair;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.predicates.InstancePresent;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.internal.RestContextImpl;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
@ -77,11 +73,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
@ -89,13 +85,6 @@ public class EC2ComputeServiceDependenciesModule extends AbstractModule {
return instanceToNodeState;
}
@Provides
@Singleton
@Named("PRESENT")
protected Predicate<RunningInstance> instancePresent(InstancePresent present) {
return new RetryablePredicate<RunningInstance>(present, 5000, 200, TimeUnit.MILLISECONDS);
}
@Override
protected void configure() {
bind(TemplateBuilder.class).to(EC2TemplateBuilderImpl.class);

View File

@ -73,7 +73,7 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
protected final Map<InstanceState, NodeState> instanceToNodeState;
@Inject
RunningInstanceToNodeMetadata(Map<InstanceState, NodeState> instanceToNodeState,
protected RunningInstanceToNodeMetadata(Map<InstanceState, NodeState> instanceToNodeState,
Map<String, Credentials> credentialStore, Map<RegionAndName, Image> instanceToImage,
@Memoized Supplier<Set<? extends Location>> locations, @Memoized Supplier<Set<? extends Hardware>> hardware) {
this.locations = checkNotNull(locations, "locations");
@ -85,13 +85,14 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
@Override
public NodeMetadata apply(RunningInstance instance) {
if (instance == null || instance.getId() == null)
return null;
NodeMetadataBuilder builder = new NodeMetadataBuilder();
String providerId = checkNotNull(instance, "instance").getId();
builder.providerId(providerId);
builder.id(instance.getRegion() + "/" + providerId);
builder.providerId(instance.getId());
builder.id(instance.getRegion() + "/" + instance.getId());
String group = getGroupForInstance(instance);
builder.group(group);
builder.credentials(credentialStore.get("node#" + instance.getRegion() + "/" + providerId));
addCredentialsForInstance(builder, instance);
builder.state(instanceToNodeState.get(instance.getInstanceState()));
builder.publicAddresses(NullSafeCollections.nullSafeSet(instance.getIpAddress()));
builder.privateAddresses(NullSafeCollections.nullSafeSet(instance.getPrivateIpAddress()));
@ -104,21 +105,25 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
RegionAndName regionAndName = new RegionAndName(instance.getRegion(), instance.getImageId());
try {
Image image = instanceToImage.get(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()
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()
}
return builder.build();
}
protected void addCredentialsForInstance(NodeMetadataBuilder builder, RunningInstance instance) {
builder.credentials(credentialStore.get("node#" + instance.getRegion() + "/" + instance.getId()));
}
protected Hardware parseHardware(final RunningInstance instance) {
Hardware hardware = getHardwareForInstance(instance);
@ -171,9 +176,8 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
} catch (NoSuchElementException e) {
logger.debug("no group parsed from %s's security groups: %s", instance.getId(), instance.getGroupIds());
} catch (IllegalArgumentException e) {
logger
.debug("too many groups match %s; %s's security groups: %s", "jclouds#", instance.getId(), instance
.getGroupIds());
logger.debug("too many groups match %s; %s's security groups: %s", "jclouds#", instance.getId(), instance
.getGroupIds());
}
return group;
}
@ -203,6 +207,8 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
}
private Location findLocationWithId(final String locationId) {
if (locationId == null)
return null;
try {
Location location = Iterables.find(locations.get(), new Predicate<Location>() {

View File

@ -89,7 +89,7 @@ public class EC2TemplateOptions extends TemplateOptions implements Cloneable {
private String keyPair = null;
private boolean noKeyPair;
private byte[] userData;
private Set<BlockDeviceMapping> blockDeviceMappings = ImmutableSet.of();
private ImmutableSet.Builder<BlockDeviceMapping> blockDeviceMappings = ImmutableSet.<BlockDeviceMapping> builder();
public static final EC2TemplateOptions NONE = new EC2TemplateOptions();
@ -142,80 +142,29 @@ public class EC2TemplateOptions extends TemplateOptions implements Cloneable {
return this;
}
/**
* Specifies the block device mappings to be used to run the instance
*/
public EC2TemplateOptions mapEBSSnapshotToDeviceName(String deviceName, String snapshotId,
@Nullable Integer sizeInGib, boolean deleteOnTermination) {
checkNotNull(deviceName, "deviceName cannot be null");
Preconditions2.checkNotEmpty(deviceName, "deviceName must be non-empty");
checkNotNull(snapshotId, "snapshotId cannot be null");
Preconditions2.checkNotEmpty(snapshotId, "snapshotId must be non-empty");
com.google.common.collect.ImmutableSet.Builder<BlockDeviceMapping> mappings = ImmutableSet
.<BlockDeviceMapping> builder();
mappings.addAll(blockDeviceMappings);
MapEBSSnapshotToDevice mapping = new MapEBSSnapshotToDevice(deviceName, snapshotId, sizeInGib,
deleteOnTermination);
mappings.add(mapping);
blockDeviceMappings = mappings.build();
blockDeviceMappings.add(new MapEBSSnapshotToDevice(deviceName, snapshotId, sizeInGib, deleteOnTermination));
return this;
}
/**
* Specifies the block device mappings to be used to run the instance
*/
public EC2TemplateOptions mapNewVolumeToDeviceName(String deviceName, int sizeInGib, boolean deleteOnTermination) {
checkNotNull(deviceName, "deviceName cannot be null");
Preconditions2.checkNotEmpty(deviceName, "deviceName must be non-empty");
com.google.common.collect.ImmutableSet.Builder<BlockDeviceMapping> mappings = ImmutableSet
.<BlockDeviceMapping> builder();
mappings.addAll(blockDeviceMappings);
MapNewVolumeToDevice mapping = new MapNewVolumeToDevice(deviceName, sizeInGib, deleteOnTermination);
mappings.add(mapping);
blockDeviceMappings = mappings.build();
blockDeviceMappings.add(new MapNewVolumeToDevice(deviceName, sizeInGib, deleteOnTermination));
return this;
}
/**
* Specifies the block device mappings to be used to run the instance
*/
public EC2TemplateOptions mapEphemeralDeviceToDeviceName(String deviceName, String virtualName) {
checkNotNull(deviceName, "deviceName cannot be null");
Preconditions2.checkNotEmpty(deviceName, "deviceName must be non-empty");
checkNotNull(virtualName, "virtualName cannot be null");
Preconditions2.checkNotEmpty(virtualName, "virtualName must be non-empty");
com.google.common.collect.ImmutableSet.Builder<BlockDeviceMapping> mappings = ImmutableSet
.<BlockDeviceMapping> builder();
mappings.addAll(blockDeviceMappings);
MapEphemeralDeviceToDevice mapping = new MapEphemeralDeviceToDevice(deviceName, virtualName);
mappings.add(mapping);
blockDeviceMappings = mappings.build();
blockDeviceMappings.add(new MapEphemeralDeviceToDevice(deviceName, virtualName));
return this;
}
/**
* Specifies the block device mappings to be used to run the instance
*/
public EC2TemplateOptions unmapDeviceNamed(String deviceName) {
checkNotNull(deviceName, "deviceName cannot be null");
Preconditions2.checkNotEmpty(deviceName, "deviceName must be non-empty");
com.google.common.collect.ImmutableSet.Builder<BlockDeviceMapping> mappings = ImmutableSet
.<BlockDeviceMapping> builder();
mappings.addAll(blockDeviceMappings);
UnmapDeviceNamed mapping = new UnmapDeviceNamed(deviceName);
mappings.add(mapping);
blockDeviceMappings = mappings.build();
blockDeviceMappings.add(new UnmapDeviceNamed(deviceName));
return this;
}
/**
* Specifies the block device mappings to be used to run the instance
*/
public EC2TemplateOptions blockDeviceMappings(Set<? extends BlockDeviceMapping> blockDeviceMappings) {
this.blockDeviceMappings = ImmutableSet.copyOf(checkNotNull(blockDeviceMappings, "blockDeviceMappings"));
public EC2TemplateOptions blockDeviceMappings(Iterable<? extends BlockDeviceMapping> blockDeviceMappings) {
this.blockDeviceMappings.addAll(checkNotNull(blockDeviceMappings, "blockDeviceMappings"));
return this;
}
@ -511,7 +460,7 @@ public class EC2TemplateOptions extends TemplateOptions implements Cloneable {
* @return BlockDeviceMapping to use when running the instance or null.
*/
public Set<BlockDeviceMapping> getBlockDeviceMappings() {
return blockDeviceMappings;
return blockDeviceMappings.build();
}
@Override

View File

@ -17,7 +17,9 @@
* ====================================================================
*/
package org.jclouds.ec2.predicates;
package org.jclouds.ec2.compute.predicates;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.NoSuchElementException;
@ -25,7 +27,7 @@ import javax.annotation.Resource;
import javax.inject.Singleton;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.logging.Logger;
import org.jclouds.rest.ResourceNotFoundException;
@ -34,13 +36,11 @@ import com.google.common.collect.Iterables;
import com.google.inject.Inject;
/**
*
* Tests to see if a task succeeds.
*
* @author Adrian Cole
*/
@Singleton
public class InstancePresent implements Predicate<RunningInstance> {
public class InstancePresent implements Predicate<RegionAndName> {
private final EC2Client client;
@ -49,13 +49,13 @@ public class InstancePresent implements Predicate<RunningInstance> {
@Inject
public InstancePresent(EC2Client client) {
this.client = client;
this.client = checkNotNull(client, "client");
}
public boolean apply(RunningInstance instance) {
logger.trace("looking for instance %s", instance);
public boolean apply(RegionAndName instance) {
logger.trace("looking for instance %s/%s", instance.getRegion(), instance.getName());
try {
instance = refresh(instance);
refresh(instance);
return true;
} catch (ResourceNotFoundException e) {
return false;
@ -64,8 +64,8 @@ public class InstancePresent implements Predicate<RunningInstance> {
}
}
private RunningInstance refresh(RunningInstance instance) {
return Iterables.getOnlyElement(Iterables.getOnlyElement(client.getInstanceServices().describeInstancesInRegion(
instance.getRegion(), instance.getId())));
protected void refresh(RegionAndName instance) {
Iterables.getOnlyElement(Iterables.getOnlyElement(client.getInstanceServices().describeInstancesInRegion(
instance.getRegion(), instance.getName())));
}
}

View File

@ -19,10 +19,10 @@
package org.jclouds.ec2.compute.strategy;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.all;
import static com.google.common.collect.Iterables.transform;
import static org.jclouds.ec2.compute.util.EC2ComputeUtils.getZoneFromLocationOrNull;
import static org.jclouds.ec2.compute.util.EC2ComputeUtils.instanceToId;
import java.util.Map;
import java.util.Set;
@ -44,6 +44,8 @@ import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet;
import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.domain.Credentials;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.compute.predicates.InstancePresent;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.options.RunInstancesOptions;
import org.jclouds.logging.Logger;
@ -51,7 +53,6 @@ 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.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
@ -76,49 +77,58 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
final Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata;
@VisibleForTesting
final ComputeUtils utils;
final Predicate<RunningInstance> instancePresent;
final InstancePresent instancePresent;
final Function<RunningInstance, Credentials> instanceToCredentials;
final Map<String, Credentials> credentialStore;
final Provider<TemplateBuilder> templateBuilderProvider;
@Inject
EC2CreateNodesInGroupThenAddToSet(
EC2Client client,
Provider<TemplateBuilder> templateBuilderProvider,
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
@Named("PRESENT") Predicate<RunningInstance> instancePresent,
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
Function<RunningInstance, Credentials> instanceToCredentials, Map<String, Credentials> credentialStore,
ComputeUtils utils) {
this.client = client;
this.templateBuilderProvider = templateBuilderProvider;
this.instancePresent = instancePresent;
this.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = createKeyPairAndSecurityGroupsAsNeededAndReturncustomize;
this.runningInstanceToNodeMetadata = runningInstanceToNodeMetadata;
this.instanceToCredentials = instanceToCredentials;
this.credentialStore = credentialStore;
this.utils = utils;
protected EC2CreateNodesInGroupThenAddToSet(
EC2Client client,
Provider<TemplateBuilder> templateBuilderProvider,
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
InstancePresent instancePresent, Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
Function<RunningInstance, Credentials> instanceToCredentials, Map<String, Credentials> credentialStore,
ComputeUtils utils) {
this.client = checkNotNull(client, "client");
this.templateBuilderProvider = checkNotNull(templateBuilderProvider, "templateBuilderProvider");
this.instancePresent = checkNotNull(instancePresent, "instancePresent");
this.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = checkNotNull(
createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
"createKeyPairAndSecurityGroupsAsNeededAndReturncustomize");
this.runningInstanceToNodeMetadata = checkNotNull(runningInstanceToNodeMetadata, "runningInstanceToNodeMetadata");
this.instanceToCredentials = checkNotNull(instanceToCredentials, "instanceToCredentials");
this.credentialStore = checkNotNull(credentialStore, "credentialStore");
this.utils = checkNotNull(utils, "utils");
}
public static Function<RunningInstance, RegionAndName> instanceToRegionAndName = new Function<RunningInstance, RegionAndName>() {
@Override
public RegionAndName apply(RunningInstance from) {
return new RegionAndName(from.getRegion(), from.getId());
}
};
@Override
public Map<?, Future<Void>> execute(String group, int count, Template template, Set<NodeMetadata> goodNodes,
Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
// ensure we don't mutate the input template
template = templateBuilderProvider.get().fromTemplate(template).build();
Iterable<? extends RunningInstance> started = createKeyPairAndSecurityGroupsAsNeededThenRunInstances(group,
count, template);
Iterable<String> ids = transform(started, instanceToId);
count, template);
Iterable<RegionAndName> ids = transform(started, instanceToRegionAndName);
String idsString = Joiner.on(',').join(ids);
if (Iterables.size(ids) > 0) {
logger.debug("<< started instances(%s)", idsString);
all(started, instancePresent);
all(ids, instancePresent);
logger.debug("<< present instances(%s)", idsString);
populateCredentials(started);
}
return utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(template.getOptions(),
transform(started, runningInstanceToNodeMetadata), goodNodes, badNodes, customizationResponses);
return utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(template.getOptions(), transform(started,
runningInstanceToNodeMetadata), goodNodes, badNodes, customizationResponses);
}
protected void populateCredentials(Iterable<? extends RunningInstance> started) {
@ -131,19 +141,20 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
if (credentials != null)
for (RunningInstance instance : started)
credentialStore.put("node#" + instance.getRegion() + "/" + instance.getId(), credentials);
}
// TODO write test for this
@VisibleForTesting
Iterable<? extends RunningInstance> createKeyPairAndSecurityGroupsAsNeededThenRunInstances(String group, int count,
Template template) {
protected Iterable<? extends RunningInstance> createKeyPairAndSecurityGroupsAsNeededThenRunInstances(String group,
int count, Template template) {
String region = AWSUtils.getRegionFromLocationOrNull(template.getLocation());
String zone = getZoneFromLocationOrNull(template.getLocation());
RunInstancesOptions instanceOptions = createKeyPairAndSecurityGroupsAsNeededAndReturncustomize.execute(region,
group, template);
group, template);
return createNodesInRegionAndZone(region, zone, count, template, instanceOptions);
}
protected Iterable<? extends RunningInstance> createNodesInRegionAndZone(String region, String zone, int count,
Template template, RunInstancesOptions instanceOptions) {
int countStarted = 0;
int tries = 0;
Iterable<? extends RunningInstance> started = ImmutableSet.<RunningInstance> of();
@ -151,12 +162,10 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
while (countStarted < count && tries++ < count) {
if (logger.isDebugEnabled())
logger.debug(">> running %d instance region(%s) zone(%s) ami(%s) params(%s)", count - countStarted, region,
zone, template.getImage().getProviderId(), instanceOptions.buildFormParameters());
zone, template.getImage().getProviderId(), instanceOptions.buildFormParameters());
started = Iterables.concat(
started,
client.getInstanceServices().runInstancesInRegion(region, zone, template.getImage().getProviderId(), 1,
count - countStarted, instanceOptions));
started = Iterables.concat(started, client.getInstanceServices().runInstancesInRegion(region, zone,
template.getImage().getProviderId(), 1, count - countStarted, instanceOptions));
countStarted = Iterables.size(started);
if (countStarted < count)

View File

@ -19,6 +19,8 @@
package org.jclouds.ec2.compute.strategy;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
@ -41,14 +43,13 @@ public class EC2DestroyNodeStrategy implements DestroyNodeStrategy {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
protected final EC2Client ec2Client;
protected final EC2Client client;
protected final GetNodeMetadataStrategy getNode;
@Inject
protected EC2DestroyNodeStrategy(EC2Client ec2Client,
GetNodeMetadataStrategy getNodeMetadataStrategy) {
this.ec2Client = ec2Client;
this.getNode = getNodeMetadataStrategy;
protected EC2DestroyNodeStrategy(EC2Client client, GetNodeMetadataStrategy getNode) {
this.client = checkNotNull(client, "client");
this.getNode = checkNotNull(getNode, "getNode");
}
@Override
@ -56,8 +57,11 @@ public class EC2DestroyNodeStrategy implements DestroyNodeStrategy {
String[] parts = AWSUtils.parseHandle(id);
String region = parts[0];
String instanceId = parts[1];
ec2Client.getInstanceServices().terminateInstancesInRegion(region,
instanceId);
destroyInstanceInRegion(region, instanceId);
return getNode.getNode(id);
}
protected void destroyInstanceInRegion(String region, String instanceId) {
client.getInstanceServices().terminateInstancesInRegion(region, instanceId);
}
}

View File

@ -19,6 +19,7 @@
package org.jclouds.ec2.compute.strategy;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.getOnlyElement;
import java.util.NoSuchElementException;
@ -31,7 +32,6 @@ import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.services.InstanceClient;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
@ -48,28 +48,27 @@ public class EC2GetNodeMetadataStrategy implements GetNodeMetadataStrategy {
@Inject
protected EC2GetNodeMetadataStrategy(EC2Client client,
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata) {
this.client = client;
this.runningInstanceToNodeMetadata = runningInstanceToNodeMetadata;
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata) {
this.client = checkNotNull(client, "client");
this.runningInstanceToNodeMetadata = checkNotNull(runningInstanceToNodeMetadata, "runningInstanceToNodeMetadata");
}
@Override
public NodeMetadata getNode(String id) {
checkNotNull(id, "id");
String[] parts = AWSUtils.parseHandle(id);
String region = parts[0];
String instanceId = parts[1];
try {
RunningInstance runningInstance = getOnlyElement(getAllRunningInstancesInRegion(client.getInstanceServices(),
region, instanceId));
RunningInstance runningInstance = getRunningInstanceInRegion(region, instanceId);
return runningInstanceToNodeMetadata.apply(runningInstance);
} catch (NoSuchElementException e) {
return null;
}
}
public static Iterable<RunningInstance> getAllRunningInstancesInRegion(InstanceClient client, String region,
String id) {
return Iterables.concat(client.describeInstancesInRegion(region, id));
public RunningInstance getRunningInstanceInRegion(String region, String id) {
return getOnlyElement(Iterables.concat(client.getInstanceServices().describeInstancesInRegion(region, id)));
}
}

View File

@ -19,10 +19,12 @@
package org.jclouds.ec2.compute.strategy;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.and;
import static com.google.common.base.Predicates.notNull;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Sets.newLinkedHashSet;
import static org.jclouds.concurrent.FutureIterables.transformParallel;
import java.util.Set;
@ -35,19 +37,20 @@ import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.ec2.EC2AsyncClient;
import org.jclouds.ec2.domain.Reservation;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.predicates.NodePredicates;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.strategy.ListNodesStrategy;
import org.jclouds.ec2.EC2AsyncClient;
import org.jclouds.ec2.domain.Reservation;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.location.Region;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
/**
*
@ -59,19 +62,19 @@ public class EC2ListNodesStrategy implements ListNodesStrategy {
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private final EC2AsyncClient client;
private final Set<String> regions;
private final Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata;
private final ExecutorService executor;
protected final EC2AsyncClient client;
protected final Set<String> regions;
protected final Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata;
protected final ExecutorService executor;
@Inject
protected EC2ListNodesStrategy(EC2AsyncClient client, @Region Set<String> regions,
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
this.client = client;
this.regions = regions;
this.runningInstanceToNodeMetadata = runningInstanceToNodeMetadata;
this.executor = executor;
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
this.client = checkNotNull(client, "client");
this.regions = checkNotNull(regions, "regions");
this.runningInstanceToNodeMetadata = checkNotNull(runningInstanceToNodeMetadata, "runningInstanceToNodeMetadata");
this.executor = checkNotNull(executor, "executor");
}
@Override
@ -81,19 +84,25 @@ public class EC2ListNodesStrategy implements ListNodesStrategy {
@Override
public Set<? extends NodeMetadata> listDetailsOnNodesMatching(Predicate<ComputeMetadata> filter) {
Iterable<? extends RunningInstance> instances = pollRunningInstances();
Iterable<? extends NodeMetadata> nodes = filter(transform(filter(instances, notNull()),
runningInstanceToNodeMetadata), and(notNull(), filter));
return ImmutableSet.copyOf(nodes);
}
protected Iterable<? extends RunningInstance> pollRunningInstances() {
Iterable<? extends Set<? extends Reservation<? extends RunningInstance>>> reservations = transformParallel(
regions, new Function<String, Future<Set<? extends Reservation<? extends RunningInstance>>>>() {
regions, new Function<String, Future<Set<? extends Reservation<? extends RunningInstance>>>>() {
@SuppressWarnings("unchecked")
@Override
public Future<Set<? extends Reservation<? extends RunningInstance>>> apply(String from) {
return (Future<Set<? extends Reservation<? extends RunningInstance>>>) client.getInstanceServices().describeInstancesInRegion(from);
}
@SuppressWarnings("unchecked")
@Override
public Future<Set<? extends Reservation<? extends RunningInstance>>> apply(String from) {
return (Future<Set<? extends Reservation<? extends RunningInstance>>>) client
.getInstanceServices().describeInstancesInRegion(from);
}
}, executor, null, logger, "reservations");
}, executor, null, logger, "reservations");
Iterable<? extends RunningInstance> instances = concat(concat(reservations));
Iterable<? extends NodeMetadata> nodes = filter(transform(instances, runningInstanceToNodeMetadata), filter);
return newLinkedHashSet(nodes);
return concat(concat(reservations));
}
}

View File

@ -21,12 +21,9 @@ package org.jclouds.ec2.compute.util;
import javax.inject.Singleton;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope;
import com.google.common.base.Function;
/**
*
* @author Adrian Cole
@ -34,13 +31,6 @@ import com.google.common.base.Function;
@Singleton
public class EC2ComputeUtils {
public static Function<RunningInstance, String> instanceToId = new Function<RunningInstance, String>() {
@Override
public String apply(RunningInstance from) {
return from.getId();
}
};
public static String getZoneFromLocationOrNull(Location location) {
return location.getScope() == LocationScope.ZONE ? location.getId() : null;
}

View File

@ -30,7 +30,64 @@ import org.jclouds.util.Preconditions2;
*
* @author Lili Nadar
*/
public class BlockDeviceMapping {
public class BlockDeviceMapping implements Comparable<BlockDeviceMapping>{
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String deviceName;
private String virtualName;
private String snapshotId;
private Integer sizeInGib;
private Boolean noDevice;
private Boolean deleteOnTermination;
public Builder deviceName(String deviceName) {
this.deviceName = deviceName;
return this;
}
public Builder virtualName(String virtualName) {
this.virtualName = virtualName;
return this;
}
public Builder snapshotId(String snapshotId) {
this.snapshotId = snapshotId;
return this;
}
public Builder sizeInGib(Integer sizeInGib) {
this.sizeInGib = sizeInGib;
return this;
}
public Builder noDevice(Boolean noDevice) {
this.noDevice = noDevice;
return this;
}
public Builder deleteOnTermination(Boolean deleteOnTermination) {
this.deleteOnTermination = deleteOnTermination;
return this;
}
public BlockDeviceMapping build() {
return new BlockDeviceMapping(deviceName, virtualName, snapshotId, sizeInGib, noDevice, deleteOnTermination);
}
public Builder clear() {
this.deviceName = null;
this.virtualName = null;
this.snapshotId = null;
this.sizeInGib = null;
this.noDevice = null;
this.deleteOnTermination = null;
return this;
}
}
private final String deviceName;
private final String virtualName;
private final String snapshotId;
@ -43,14 +100,14 @@ public class BlockDeviceMapping {
private static final Integer VOLUME_SIZE_MAX_VALUE = 1000;
BlockDeviceMapping(String deviceName, @Nullable String virtualName, @Nullable String snapshotId,
@Nullable Integer sizeInGib, @Nullable Boolean noDevice, @Nullable Boolean deleteOnTermination) {
@Nullable Integer sizeInGib, @Nullable Boolean noDevice, @Nullable Boolean deleteOnTermination) {
checkNotNull(deviceName, "deviceName cannot be null");
Preconditions2.checkNotEmpty(deviceName, "the deviceName must be non-empty");
if (sizeInGib != null) {
checkArgument((sizeInGib >= VOLUME_SIZE_MIN_VALUE && sizeInGib <= VOLUME_SIZE_MAX_VALUE), String.format(
"Size in Gib must be between %s and %s GB", VOLUME_SIZE_MIN_VALUE, VOLUME_SIZE_MAX_VALUE));
checkArgument((sizeInGib >= VOLUME_SIZE_MIN_VALUE && sizeInGib <= VOLUME_SIZE_MAX_VALUE),
String.format("Size in Gib must be between %s and %s GB", VOLUME_SIZE_MIN_VALUE, VOLUME_SIZE_MAX_VALUE));
}
this.deviceName = deviceName;
this.virtualName = virtualName;
@ -142,13 +199,13 @@ public class BlockDeviceMapping {
@Override
public String toString() {
return "[deviceName=" + deviceName + ", virtualName=" + virtualName + ", snapshotId=" + snapshotId
+ ", sizeInGib=" + sizeInGib + ", noDevice=" + noDevice + ", deleteOnTermination=" + deleteOnTermination
+ "]";
+ ", sizeInGib=" + sizeInGib + ", noDevice=" + noDevice + ", deleteOnTermination=" + deleteOnTermination
+ "]";
}
public static class MapEBSSnapshotToDevice extends BlockDeviceMapping {
public MapEBSSnapshotToDevice(String deviceName, String snapshotId, @Nullable Integer sizeInGib,
@Nullable Boolean deleteOnTermination) {
@Nullable Boolean deleteOnTermination) {
super(deviceName, null, snapshotId, sizeInGib, null, deleteOnTermination);
checkNotNull(snapshotId, "snapshotId cannot be null");
Preconditions2.checkNotEmpty(snapshotId, "the snapshotId must be non-empty");
@ -175,4 +232,9 @@ public class BlockDeviceMapping {
super(deviceName, null, null, null, true, null);
}
}
@Override
public int compareTo(BlockDeviceMapping arg0) {
return deviceName.compareTo(arg0.deviceName);
}
}

View File

@ -39,6 +39,9 @@ import com.google.common.collect.Sets;
* @author Adrian Cole
*/
public class RunningInstance implements Comparable<RunningInstance> {
public static Builder builder() {
return new Builder();
}
public static class Builder {
protected String region;
@ -265,8 +268,8 @@ public class RunningInstance implements Comparable<RunningInstance> {
this.ipAddress = ipAddress;
this.kernelId = kernelId;
this.keyName = keyName;
this.launchTime = checkNotNull(launchTime, "launchTime");
this.availabilityZone = checkNotNull(availabilityZone, "availabilityZone");
this.launchTime = launchTime;// nullable on spot.
this.availabilityZone = availabilityZone;// nullable on spot.
this.virtualizationType = virtualizationType;
this.platform = platform;
this.privateDnsName = privateDnsName;// nullable on runinstances.

View File

@ -58,10 +58,6 @@ public class RunInstancesOptions extends BaseEC2RequestOptions {
return this;
}
String getKeyName() {
return getFirstFormOrNull("KeyName");
}
/**
* Attach multiple security groups
*/
@ -88,10 +84,6 @@ public class RunInstancesOptions extends BaseEC2RequestOptions {
return withSecurityGroups(securityGroup);
}
String getSecurityGroup() {
return getFirstFormOrNull("SecurityGroup.1");
}
/**
* Unencoded data
*/
@ -103,10 +95,6 @@ public class RunInstancesOptions extends BaseEC2RequestOptions {
return this;
}
String getUserData() {
return getFirstFormOrNull("UserData");
}
/**
* Specifies the instance type. default small;
*/
@ -115,10 +103,6 @@ public class RunInstancesOptions extends BaseEC2RequestOptions {
return this;
}
String getType() {
return getFirstFormOrNull("InstanceType");
}
/**
* The ID of the kernel with which to launch the instance.
*/
@ -127,10 +111,6 @@ public class RunInstancesOptions extends BaseEC2RequestOptions {
return this;
}
String getKernelId() {
return getFirstFormOrNull("KernelId");
}
/**
* The ID of the RAM disk with which to launch the instance. Some kernels require additional
* drivers at l aunch. Check the kernel requirements for information on whether you need to
@ -142,15 +122,10 @@ public class RunInstancesOptions extends BaseEC2RequestOptions {
return this;
}
String getRamdiskId() {
return getFirstFormOrNull("RamdiskId");
}
/**
* Specifies the Block Device Mapping for the instance
*
*/
public RunInstancesOptions withBlockDeviceMappings(Set<? extends BlockDeviceMapping> mappings) {
int i = 1;
for (BlockDeviceMapping mapping : checkNotNull(mappings, "mappings")) {
@ -161,15 +136,14 @@ public class RunInstancesOptions extends BaseEC2RequestOptions {
if (mapping.getEbsSnapshotId() != null)
formParameters.put(String.format("BlockDeviceMapping.%d.Ebs.SnapshotId", i), mapping.getEbsSnapshotId());
if (mapping.getEbsVolumeSize() != null)
formParameters.put(String.format("BlockDeviceMapping.%d.Ebs.VolumeSize", i), String.valueOf(mapping
.getEbsVolumeSize()));
formParameters.put(String.format("BlockDeviceMapping.%d.Ebs.VolumeSize", i),
String.valueOf(mapping.getEbsVolumeSize()));
if (mapping.getEbsNoDevice() != null)
formParameters.put(String.format("BlockDeviceMapping.%d.Ebs.NoDevice", i), String.valueOf(mapping
.getEbsNoDevice()));
formParameters.put(String.format("BlockDeviceMapping.%d.Ebs.NoDevice", i),
String.valueOf(mapping.getEbsNoDevice()));
if (mapping.getEbsDeleteOnTermination() != null)
formParameters.put(String.format("BlockDeviceMapping.%d.Ebs.DeleteOnTermination", i), String
.valueOf(mapping.getEbsDeleteOnTermination()));
formParameters.put(String.format("BlockDeviceMapping.%d.Ebs.DeleteOnTermination", i),
String.valueOf(mapping.getEbsDeleteOnTermination()));
i++;
}
return this;

View File

@ -26,8 +26,9 @@ import java.util.Set;
import org.jclouds.http.options.BaseHttpRequestOptions;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
/**
*
@ -51,7 +52,7 @@ public class BaseEC2RequestOptions extends BaseHttpRequestOptions {
}
protected Set<String> getFormValuesWithKeysPrefixedBy(final String prefix) {
Set<String> values = Sets.newLinkedHashSet();
Builder<String> values = ImmutableSet.<String> builder();
for (String key : Iterables.filter(formParameters.keySet(), new Predicate<String>() {
public boolean apply(String input) {
@ -59,10 +60,9 @@ public class BaseEC2RequestOptions extends BaseHttpRequestOptions {
}
})) {
values.add(formParameters.get(key).iterator().next());
values.add(Iterables.get(formParameters.get(key), 0));
}
return values;
return values.build();
}
}

View File

@ -42,8 +42,10 @@ import org.jclouds.domain.Location;
import org.jclouds.domain.LocationBuilder;
import org.jclouds.domain.LocationScope;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.compute.functions.RunningInstanceToNodeMetadata;
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
import org.jclouds.ec2.compute.predicates.InstancePresent;
import org.jclouds.ec2.domain.Reservation;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.options.RunInstancesOptions;
@ -51,7 +53,6 @@ import org.jclouds.ec2.services.InstanceClient;
import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
@ -61,7 +62,7 @@ import com.google.inject.util.Providers;
* @author Adrian Cole
*/
@Test(groups = "unit")
public class EC2RunNodesAndAddToSetStrategyTest {
public class EC2CreateNodesInGroupThenAddToSetTest {
@Test
public void testZoneAsALocation() {
@ -126,10 +127,10 @@ public class EC2RunNodesAndAddToSetStrategyTest {
// simulate a lazy credentials fetch
Credentials creds = new Credentials("foo", "bar");
expect(strategy.instanceToCredentials.apply(instance)).andReturn(creds);
expect(instance.getRegion()).andReturn(region);
expect(instance.getRegion()).andReturn(region).atLeastOnce();
expect(strategy.credentialStore.put("node#" + region + "/" + instanceCreatedId, creds)).andReturn(null);
expect(strategy.instancePresent.apply(instance)).andReturn(true);
expect(strategy.instancePresent.apply(new RegionAndName(region, instanceCreatedId))).andReturn(true);
expect(input.template.getOptions()).andReturn(input.options).atLeastOnce();
expect(strategy.runningInstanceToNodeMetadata.apply(instance)).andReturn(nodeMetadata);
@ -220,13 +221,13 @@ public class EC2RunNodesAndAddToSetStrategyTest {
private EC2CreateNodesInGroupThenAddToSet setupStrategy(TemplateBuilder template) {
EC2Client client = createMock(EC2Client.class);
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = createMock(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.class);
Predicate<RunningInstance> instanceStateRunning = createMock(Predicate.class);
InstancePresent instancePresent = createMock(InstancePresent.class);
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata = createMock(RunningInstanceToNodeMetadata.class);
Function<RunningInstance, Credentials> instanceToCredentials = createMock(Function.class);
Map<String, Credentials> credentialStore = createMock(Map.class);
ComputeUtils utils = createMock(ComputeUtils.class);
return new EC2CreateNodesInGroupThenAddToSet(client, Providers.<TemplateBuilder> of(template),
createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, instanceStateRunning,
createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, instancePresent,
runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils);
}

View File

@ -65,6 +65,8 @@ public class NodePresentAndInIntendedState implements Predicate<NodeMetadata> {
}
private NodeMetadata refresh(NodeMetadata node) {
if (node == null || node.getId() == null)
return null;
return client.getNodeMetadata(node.getId());
}
}

View File

@ -22,6 +22,7 @@ package org.jclouds.compute.strategy;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Throwables.getRootCause;
import static java.lang.String.format;
import static org.jclouds.compute.util.ComputeServiceUtils.findReachableSocketOnNode;
import java.util.Map;
@ -36,6 +37,7 @@ import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen;
import org.jclouds.compute.reference.ComputeServiceConstants;
@ -125,15 +127,24 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
public Void call() {
checkState(!tainted, "this object is not designed to be reused: %s", toString());
tainted = true;
String originalId = node.getId();
NodeMetadata originalNode = node;
try {
if (options.shouldBlockUntilRunning()) {
if (nodeRunning.apply(node)) {
node = getNode.getNode(node.getId());
node = getNode.getNode(originalId);
} else {
throw new IllegalStateException(String.format(
"node didn't achieve the state running on node %s within %d seconds, final state: %s", node
.getId(), timeouts.nodeRunning / 1000, node.getState()));
NodeMetadata nodeForState = getNode.getNode(originalId);
NodeState state = nodeForState == null ? NodeState.TERMINATED : nodeForState.getState();
if (state == NodeState.TERMINATED)
throw new IllegalStateException(format("node(%s) terminated before we could customize", originalId));
else
throw new IllegalStateException(format(
"node(%s) didn't achieve the state running within %d seconds, final state: %s", originalId,
timeouts.nodeRunning / 1000, state));
}
if (node == null)
throw new IllegalStateException(format("node %s terminated before applying options", originalId));
if (statement != null) {
RunScriptOnNode runner = initScriptRunnerFactory.create(node, statement, options, badNodes).call();
if (runner != null) {
@ -145,11 +156,11 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
findReachableSocketOnNode(socketTester.seconds(options.getSeconds()), node, options.getPort());
}
}
logger.debug("<< options applied node(%s)", node.getId());
logger.debug("<< options applied node(%s)", originalId);
goodNodes.add(node);
} catch (Exception e) {
logger.error(e, "<< problem applying options to node(%s): ", node.getId(), getRootCause(e).getMessage());
badNodes.put(node, e);
logger.error(e, "<< problem applying options to node(%s): ", originalId, getRootCause(e).getMessage());
badNodes.put(node == null ? originalNode : node, e);
}
return null;
}

View File

@ -301,7 +301,7 @@ public class TemplateBuilderImplTest {
TemplateBuilder defaultTemplate = createMock(TemplateBuilder.class);
expect(templateBuilderProvider.get()).andReturn(defaultTemplate);
expect(defaultTemplate.options(options)).andReturn(defaultTemplate);
expect(defaultTemplate.options(from)).andReturn(defaultTemplate);
expect(defaultTemplate.build()).andReturn(null);
expect(optionsProvider.get()).andReturn(from).atLeastOnce();

View File

@ -0,0 +1,144 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.compute.strategy;
import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify;
import static org.testng.Assert.assertEquals;
import java.util.Map;
import java.util.Set;
import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.functions.TemplateOptionsToStatement;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen;
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
import org.jclouds.scriptbuilder.domain.Statement;
import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
/**
* @author Adrian Cole
*/
@Test(groups = "unit")
public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest {
@SuppressWarnings("unchecked")
public void testBreakWhenNodeStillPending() {
Predicate<NodeMetadata> nodeRunning = createMock(Predicate.class);
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory = createMock(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class);
GetNodeMetadataStrategy getNode = createMock(GetNodeMetadataStrategy.class);
RetryIfSocketNotYetOpen socketTester = createMock(RetryIfSocketNotYetOpen.class);
Timeouts timeouts = new Timeouts();
Function<TemplateOptions, Statement> templateOptionsToStatement = new TemplateOptionsToStatement();
@SuppressWarnings("unused")
Statement statement = null;
TemplateOptions options = new TemplateOptions();
Set<NodeMetadata> goodNodes = Sets.newLinkedHashSet();
Map<NodeMetadata, Exception> badNodes = Maps.newLinkedHashMap();
Multimap<NodeMetadata, CustomizationResponse> customizationResponses = LinkedHashMultimap.create();
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.PENDING).build();
// node never reached running state
expect(nodeRunning.apply(node)).andReturn(false);
expect(getNode.getNode(node.getId())).andReturn(node);
// replay mocks
replay(nodeRunning);
replay(initScriptRunnerFactory);
replay(getNode);
replay(socketTester);
// run
new CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(nodeRunning, getNode, socketTester, timeouts,
templateOptionsToStatement, initScriptRunnerFactory, options, node, goodNodes, badNodes,
customizationResponses).apply(node);
assertEquals(goodNodes.size(), 0);
assertEquals(badNodes.keySet(), ImmutableSet.of(node));
assertEquals(badNodes.get(node).getMessage(),
"node(id) didn't achieve the state running within 1200 seconds, final state: PENDING");
assertEquals(customizationResponses.size(), 0);
// verify mocks
verify(nodeRunning);
verify(initScriptRunnerFactory);
verify(getNode);
verify(socketTester);
}
@SuppressWarnings("unchecked")
public void testBreakGraceFullyWhenNodeDied() {
Predicate<NodeMetadata> nodeRunning = createMock(Predicate.class);
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory = createMock(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class);
GetNodeMetadataStrategy getNode = createMock(GetNodeMetadataStrategy.class);
RetryIfSocketNotYetOpen socketTester = createMock(RetryIfSocketNotYetOpen.class);
Timeouts timeouts = new Timeouts();
Function<TemplateOptions, Statement> templateOptionsToStatement = new TemplateOptionsToStatement();
@SuppressWarnings("unused")
Statement statement = null;
TemplateOptions options = new TemplateOptions();
Set<NodeMetadata> goodNodes = Sets.newLinkedHashSet();
Map<NodeMetadata, Exception> badNodes = Maps.newLinkedHashMap();
Multimap<NodeMetadata, CustomizationResponse> customizationResponses = LinkedHashMultimap.create();
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.PENDING).build();
// node never reached running state
expect(nodeRunning.apply(node)).andReturn(false);
expect(getNode.getNode(node.getId())).andReturn(null);
// replay mocks
replay(nodeRunning);
replay(initScriptRunnerFactory);
replay(getNode);
replay(socketTester);
// run
new CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(nodeRunning, getNode, socketTester, timeouts,
templateOptionsToStatement, initScriptRunnerFactory, options, node, goodNodes, badNodes,
customizationResponses).apply(node);
assertEquals(goodNodes.size(), 0);
assertEquals(badNodes.keySet(), ImmutableSet.of(node));
assertEquals(badNodes.get(node).getMessage(), "node(id) terminated before we could customize");
assertEquals(customizationResponses.size(), 0);
// verify mocks
verify(nodeRunning);
verify(initScriptRunnerFactory);
verify(getNode);
verify(socketTester);
}
}

View File

@ -19,14 +19,16 @@
package org.jclouds.predicates;
import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
import java.util.Date;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.annotation.Resource;
import org.jclouds.logging.Logger;
import org.jclouds.util.Throwables2;
import com.google.common.base.Predicate;
@ -75,10 +77,16 @@ public class RetryablePredicate<T> implements Predicate<T> {
} catch (InterruptedException e) {
logger.warn(e, "predicate %s on %s interrupted, returning false", input, predicate);
} catch (RuntimeException e) {
ExecutionException exec = Throwables2.getFirstThrowableOfType(e, ExecutionException.class);
if (exec != null)
logger.warn(exec, "predicate %s on %s error, returning false", input, predicate);
else
if (getFirstThrowableOfType(e, ExecutionException.class) != null) {
logger.warn(e, "predicate %s on %s errored [%s], returning false", input, predicate, e.getMessage());
return false;
} else if (getFirstThrowableOfType(e, IllegalStateException.class) != null) {
logger.warn(e, "predicate %s on %s illegal state [%s], returning false", input, predicate, e.getMessage());
return false;
} else if (getFirstThrowableOfType(e, TimeoutException.class) != null) {
logger.warn(e, "predicate %s on %s timed out [%s], returning false", input, predicate, e.getMessage());
return false;
} else
throw e;
}
return false;

View File

@ -20,12 +20,15 @@
package org.jclouds.predicates;
import java.util.Date;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier;
/**
*
@ -36,6 +39,56 @@ import com.google.common.base.Predicates;
public class RetryablePredicateTest {
public static int SLOW_BUILD_SERVER_GRACE = 50;
@Test
void testFalseOnIllegalStateExeception() {
ensureImmediateReturnFor(new IllegalStateException());
}
@SuppressWarnings("serial")
@Test
void testFalseOnExecutionException() {
ensureImmediateReturnFor(new ExecutionException() {
});
}
@SuppressWarnings("serial")
@Test
void testFalseOnTimeoutException() {
ensureImmediateReturnFor(new TimeoutException() {
});
}
@SuppressWarnings("serial")
@Test(expectedExceptions = RuntimeException.class)
void testPropagateOnException() {
ensureImmediateReturnFor(new Exception() {
});
}
private void ensureImmediateReturnFor(final Exception ex) {
RetryablePredicate<Supplier<String>> predicate = new RetryablePredicate<Supplier<String>>(
new Predicate<Supplier<String>>() {
@Override
public boolean apply(Supplier<String> input) {
return "goo".equals(input.get());
}
}, 3, 1, TimeUnit.SECONDS);
Date startPlusThird = new Date(System.currentTimeMillis() + 1000);
assert !predicate.apply(new Supplier<String>() {
@Override
public String get() {
throw new RuntimeException(ex);
}
});
Date now = new Date();
assert now.compareTo(startPlusThird) < 0 : String.format("%s should be less than %s", now.getTime(),
startPlusThird.getTime());
}
@Test
void testAlwaysTrue() {
RetryablePredicate<String> predicate = new RetryablePredicate<String>(Predicates.<String> alwaysTrue(), 3, 1,

View File

@ -24,6 +24,7 @@ import org.jclouds.aws.ec2.services.AWSInstanceAsyncClient;
import org.jclouds.aws.ec2.services.AWSKeyPairAsyncClient;
import org.jclouds.aws.ec2.services.MonitoringAsyncClient;
import org.jclouds.aws.ec2.services.PlacementGroupAsyncClient;
import org.jclouds.aws.ec2.services.SpotInstanceAsyncClient;
import org.jclouds.ec2.EC2AsyncClient;
import org.jclouds.rest.annotations.Delegate;
@ -67,4 +68,10 @@ public interface AWSEC2AsyncClient extends EC2AsyncClient {
@Delegate
@Override
AWSKeyPairAsyncClient getKeyPairServices();
/**
* Provides asynchronous access to SpotInstance services.
*/
@Delegate
SpotInstanceAsyncClient getSpotInstanceServices();
}

View File

@ -26,6 +26,7 @@ import org.jclouds.aws.ec2.services.AWSInstanceClient;
import org.jclouds.aws.ec2.services.AWSKeyPairClient;
import org.jclouds.aws.ec2.services.MonitoringClient;
import org.jclouds.aws.ec2.services.PlacementGroupClient;
import org.jclouds.aws.ec2.services.SpotInstanceClient;
import org.jclouds.concurrent.Timeout;
import org.jclouds.ec2.EC2Client;
import org.jclouds.rest.annotations.Delegate;
@ -70,4 +71,10 @@ public interface AWSEC2Client extends EC2Client {
@Delegate
@Override
AWSKeyPairClient getKeyPairServices();
/**
* Provides synchronous access to SpotInstance services.
*/
@Delegate
SpotInstanceClient getSpotInstanceServices();
}

View File

@ -0,0 +1,65 @@
package org.jclouds.aws.ec2.binders;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import java.util.Map.Entry;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.domain.LaunchSpecification;
import org.jclouds.aws.ec2.options.AWSRunInstancesOptions;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.utils.ModifyRequest;
import org.jclouds.rest.Binder;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.Multimaps;
/**
*
* @author Adrian Cole
*/
@Singleton
public class BindLaunchSpecificationToFormParams implements Binder, Function<LaunchSpecification, Map<String, String>> {
@Override
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
checkArgument(input instanceof LaunchSpecification, "this binder is only valid for LaunchSpecifications!");
LaunchSpecification launchSpec = LaunchSpecification.class.cast(input);
return ModifyRequest.putFormParams(request, Multimaps.forMap(apply(launchSpec)));
}
@Override
public Map<String, String> apply(LaunchSpecification launchSpec) {
Builder<String, String> builder = ImmutableMap.<String, String> builder();
builder.put("LaunchSpecification.ImageId", checkNotNull(launchSpec.getImageId(), "imageId"));
if (launchSpec.getAvailabilityZone() != null)
builder.put("LaunchSpecification.Placement.AvailabilityZone", launchSpec.getAvailabilityZone());
AWSRunInstancesOptions options = new AWSRunInstancesOptions();
if (launchSpec.getBlockDeviceMappings().size() > 0)
options.withBlockDeviceMappings(launchSpec.getBlockDeviceMappings());
if (launchSpec.getGroupIds().size() > 0)
options.withSecurityGroups(launchSpec.getGroupIds());
options.asType(checkNotNull(launchSpec.getInstanceType(), "instanceType"));
if (launchSpec.getKernelId() != null)
options.withKernelId(launchSpec.getKernelId());
if (launchSpec.getKeyName() != null)
options.withKeyName(launchSpec.getKeyName());
if (launchSpec.getRamdiskId() != null)
options.withRamdisk(launchSpec.getRamdiskId());
if (Boolean.TRUE.equals(launchSpec.isMonitoringEnabled()))
options.enableMonitoring();
if (launchSpec.getUserData() != null)
options.withUserData(launchSpec.getUserData());
for (Entry<String, String> entry : options.buildFormParameters().entries()) {
builder.put("LaunchSpecification." + entry.getKey(), entry.getValue());
}
return builder.build();
}
}

View File

@ -0,0 +1,40 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.binders;
import javax.inject.Singleton;
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.Binder;
/**
* Binds the String [] to form parameters named with SpotInstanceRequestId.index
*
* @author Adrian Cole
*/
@Singleton
public class BindSpotInstanceRequestIdsToIndexedFormParams implements Binder {
@Override
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
return AWSUtils.indexStringArrayToFormValuesWithPrefix(request, "SpotInstanceRequestId", input);
}
}

View File

@ -27,6 +27,7 @@ import java.util.Set;
import javax.annotation.Nullable;
import org.jclouds.aws.ec2.options.RequestSpotInstancesOptions;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.domain.Credentials;
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
@ -73,6 +74,10 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
eTo.noPlacementGroup();
if (getPlacementGroup() != null)
eTo.placementGroup(getPlacementGroup());
if (getSpotPrice() != null)
eTo.spotPrice(getSpotPrice());
if (getSpotOptions() != null)
eTo.spotOptions(getSpotOptions());
}
}
@ -80,6 +85,8 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
private String placementGroup = null;
private boolean noPlacementGroup;
private String subnetId;
private Float spotPrice;
private RequestSpotInstancesOptions spotOptions = RequestSpotInstancesOptions.NONE;
public static final AWSEC2TemplateOptions NONE = new AWSEC2TemplateOptions();
@ -123,6 +130,22 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
return this;
}
/**
* Specifies the maximum spot price to use
*/
public AWSEC2TemplateOptions spotPrice(Float spotPrice) {
this.spotPrice = spotPrice;
return this;
}
/**
* Options for starting spot instances
*/
public AWSEC2TemplateOptions spotOptions(RequestSpotInstancesOptions spotOptions) {
this.spotOptions = spotOptions != null ? spotOptions : RequestSpotInstancesOptions.NONE;
return this;
}
public static class Builder {
/**
* @see EC2TemplateOptions#blockDeviceMappings
@ -136,7 +159,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
* @see EC2TemplateOptions#mapEBSSnapshotToDeviceName
*/
public static AWSEC2TemplateOptions mapEBSSnapshotToDeviceName(String deviceName, String snapshotId,
@Nullable Integer sizeInGib, boolean deleteOnTermination) {
@Nullable Integer sizeInGib, boolean deleteOnTermination) {
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
return options.mapEBSSnapshotToDeviceName(deviceName, snapshotId, sizeInGib, deleteOnTermination);
}
@ -145,7 +168,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
* @see EC2TemplateOptions#mapNewVolumeToDeviceName
*/
public static AWSEC2TemplateOptions mapNewVolumeToDeviceName(String deviceName, int sizeInGib,
boolean deleteOnTermination) {
boolean deleteOnTermination) {
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
return options.mapNewVolumeToDeviceName(deviceName, sizeInGib, deleteOnTermination);
}
@ -280,12 +303,28 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
}
/**
* @see TemplateOptions#withSubnetId
* @see TemplateOptions#spotPrice
*/
public static AWSEC2TemplateOptions subnetId(String subnetId) {
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
return options.subnetId(subnetId);
}
/**
* @see TemplateOptions#spotPrice
*/
public static AWSEC2TemplateOptions spotPrice(Float spotPrice) {
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
return options.spotPrice(spotPrice);
}
/**
* @see TemplateOptions#spotOptions
*/
public static AWSEC2TemplateOptions spotOptions(RequestSpotInstancesOptions spotOptions) {
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
return options.spotOptions(spotOptions);
}
}
// methods that only facilitate returning the correct object type
@ -294,7 +333,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
* {@inheritDoc}
*/
@Override
public AWSEC2TemplateOptions blockDeviceMappings(Set<? extends BlockDeviceMapping> blockDeviceMappings) {
public AWSEC2TemplateOptions blockDeviceMappings(Iterable<? extends BlockDeviceMapping> blockDeviceMappings) {
return AWSEC2TemplateOptions.class.cast(super.blockDeviceMappings(blockDeviceMappings));
}
@ -312,9 +351,9 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
@Override
public AWSEC2TemplateOptions mapEBSSnapshotToDeviceName(String deviceName, String snapshotId, Integer sizeInGib,
boolean deleteOnTermination) {
boolean deleteOnTermination) {
return AWSEC2TemplateOptions.class.cast(super.mapEBSSnapshotToDeviceName(deviceName, snapshotId, sizeInGib,
deleteOnTermination));
deleteOnTermination));
}
/**
@ -331,7 +370,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
@Override
public AWSEC2TemplateOptions mapNewVolumeToDeviceName(String deviceName, int sizeInGib, boolean deleteOnTermination) {
return AWSEC2TemplateOptions.class.cast(super
.mapNewVolumeToDeviceName(deviceName, sizeInGib, deleteOnTermination));
.mapNewVolumeToDeviceName(deviceName, sizeInGib, deleteOnTermination));
}
/**
@ -525,6 +564,20 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
return subnetId;
}
/**
* @return maximum spot price or null.
*/
public Float getSpotPrice() {
return spotPrice;
}
/**
* @return options for controlling spot instance requests.
*/
public RequestSpotInstancesOptions getSpotOptions() {
return spotOptions;
}
@Override
public int hashCode() {
final int prime = 31;
@ -532,6 +585,8 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
result = prime * result + (monitoringEnabled ? 1231 : 1237);
result = prime * result + (noPlacementGroup ? 1231 : 1237);
result = prime * result + ((placementGroup == null) ? 0 : placementGroup.hashCode());
result = prime * result + ((spotOptions == null) ? 0 : spotOptions.hashCode());
result = prime * result + ((spotPrice == null) ? 0 : spotPrice.hashCode());
result = prime * result + ((subnetId == null) ? 0 : subnetId.hashCode());
return result;
}
@ -554,6 +609,16 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
return false;
} else if (!placementGroup.equals(other.placementGroup))
return false;
if (spotOptions == null) {
if (other.spotOptions != null)
return false;
} else if (!spotOptions.equals(other.spotOptions))
return false;
if (spotPrice == null) {
if (other.spotPrice != null)
return false;
} else if (!spotPrice.equals(other.spotPrice))
return false;
if (subnetId == null) {
if (other.subnetId != null)
return false;
@ -566,9 +631,10 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
public String toString() {
return "[groupIds=" + getGroupIds() + ", keyPair=" + getKeyPair() + ", noKeyPair="
+ !shouldAutomaticallyCreateKeyPair() + ", monitoringEnabled=" + monitoringEnabled + ", placementGroup="
+ placementGroup + ", noPlacementGroup=" + noPlacementGroup + ", subnetId=" + subnetId + ", userData="
+ Arrays.toString(getUserData()) + ", blockDeviceMappings=" + getBlockDeviceMappings() + "]";
+ !shouldAutomaticallyCreateKeyPair() + ", monitoringEnabled=" + monitoringEnabled + ", placementGroup="
+ placementGroup + ", noPlacementGroup=" + noPlacementGroup + ", subnetId=" + subnetId + ", userData="
+ Arrays.toString(getUserData()) + ", blockDeviceMappings=" + getBlockDeviceMappings() + ", spotPrice="
+ spotPrice + ", spotOptions=" + spotOptions + "]";
}
}

View File

@ -22,14 +22,26 @@ package org.jclouds.aws.ec2.compute.config;
import static org.jclouds.compute.domain.OsFamily.AMZN_LINUX;
import org.jclouds.aws.ec2.compute.AWSEC2TemplateBuilderImpl;
import org.jclouds.aws.ec2.compute.functions.AWSRunningInstanceToNodeMetadata;
import org.jclouds.aws.ec2.compute.predicates.AWSEC2InstancePresent;
import org.jclouds.aws.ec2.compute.strategy.AWSEC2CreateNodesInGroupThenAddToSet;
import org.jclouds.aws.ec2.compute.strategy.AWSEC2DestroyNodeStrategy;
import org.jclouds.aws.ec2.compute.strategy.AWSEC2GetNodeMetadataStrategy;
import org.jclouds.aws.ec2.compute.strategy.AWSEC2ListNodesStrategy;
import org.jclouds.aws.ec2.compute.strategy.AWSEC2ReviseParsedImage;
import org.jclouds.aws.ec2.compute.strategy.CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions;
import org.jclouds.aws.ec2.compute.suppliers.AWSEC2HardwareSupplier;
import org.jclouds.aws.ec2.compute.suppliers.AWSRegionAndNameToImageSupplier;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.ec2.compute.config.EC2ComputeServiceContextModule;
import org.jclouds.ec2.compute.functions.RunningInstanceToNodeMetadata;
import org.jclouds.ec2.compute.internal.EC2TemplateBuilderImpl;
import org.jclouds.ec2.compute.predicates.InstancePresent;
import org.jclouds.ec2.compute.strategy.CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions;
import org.jclouds.ec2.compute.strategy.EC2CreateNodesInGroupThenAddToSet;
import org.jclouds.ec2.compute.strategy.EC2DestroyNodeStrategy;
import org.jclouds.ec2.compute.strategy.EC2GetNodeMetadataStrategy;
import org.jclouds.ec2.compute.strategy.EC2ListNodesStrategy;
import org.jclouds.ec2.compute.strategy.ReviseParsedImage;
import org.jclouds.ec2.compute.suppliers.EC2HardwareSupplier;
import org.jclouds.ec2.compute.suppliers.RegionAndNameToImageSupplier;
@ -56,6 +68,12 @@ public class AWSEC2ComputeServiceContextModule extends EC2ComputeServiceContextM
bind(EC2HardwareSupplier.class).to(AWSEC2HardwareSupplier.class);
bind(RegionAndNameToImageSupplier.class).to(AWSRegionAndNameToImageSupplier.class);
bind(EC2TemplateBuilderImpl.class).to(AWSEC2TemplateBuilderImpl.class);
bind(EC2GetNodeMetadataStrategy.class).to(AWSEC2GetNodeMetadataStrategy.class);
bind(EC2ListNodesStrategy.class).to(AWSEC2ListNodesStrategy.class);
bind(EC2DestroyNodeStrategy.class).to(AWSEC2DestroyNodeStrategy.class);
bind(InstancePresent.class).to(AWSEC2InstancePresent.class);
bind(EC2CreateNodesInGroupThenAddToSet.class).to(AWSEC2CreateNodesInGroupThenAddToSet.class);
bind(RunningInstanceToNodeMetadata.class).to(AWSRunningInstanceToNodeMetadata.class);
}
@Override

View File

@ -0,0 +1,69 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.compute.functions;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.compute.functions.RunningInstanceToNodeMetadata;
import org.jclouds.ec2.domain.InstanceState;
import org.jclouds.ec2.domain.RunningInstance;
import com.google.common.base.Supplier;
/**
* @author Adrian Cole
*/
@Singleton
public class AWSRunningInstanceToNodeMetadata extends RunningInstanceToNodeMetadata {
@Inject
protected AWSRunningInstanceToNodeMetadata(Map<InstanceState, NodeState> instanceToNodeState,
Map<String, Credentials> credentialStore, Map<RegionAndName, Image> instanceToImage,
@Memoized Supplier<Set<? extends Location>> locations, @Memoized Supplier<Set<? extends Hardware>> hardware) {
super(instanceToNodeState, credentialStore, instanceToImage, locations, hardware);
}
@Override
protected void addCredentialsForInstance(NodeMetadataBuilder builder, RunningInstance instance) {
Credentials creds = credentialStore.get("node#" + instance.getRegion() + "/" + instance.getId());
String spotRequestId = AWSRunningInstance.class.cast(instance).getSpotInstanceRequestId();
if (creds == null && spotRequestId != null) {
creds = credentialStore.get("node#" + instance.getRegion() + "/" + spotRequestId);
if (creds != null)
credentialStore.put("node#" + instance.getRegion() + "/" + instance.getId(), creds);
}
if (creds != null)
builder.credentials(creds);
}
}

View File

@ -0,0 +1,56 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.compute.predicates;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.AWSEC2Client;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.compute.predicates.InstancePresent;
import com.google.common.collect.Iterables;
import com.google.inject.Inject;
/**
*
* @author Adrian Cole
*/
@Singleton
public class AWSEC2InstancePresent extends InstancePresent {
private final AWSEC2Client client;
@Inject
public AWSEC2InstancePresent(AWSEC2Client client) {
super(client);
this.client = checkNotNull(client, "client");
}
@Override
protected void refresh(RegionAndName instance) {
if (instance.getName().indexOf("sir-") != 0)
super.refresh(instance);
else
Iterables.getOnlyElement(client.getSpotInstanceServices().describeSpotInstanceRequestsInRegion(
instance.getRegion(), instance.getName()));
}
}

View File

@ -0,0 +1,109 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.compute.strategy;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.AWSEC2Client;
import org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions;
import org.jclouds.aws.ec2.compute.predicates.AWSEC2InstancePresent;
import org.jclouds.aws.ec2.domain.LaunchSpecification;
import org.jclouds.aws.ec2.functions.SpotInstanceRequestToAWSRunningInstance;
import org.jclouds.aws.ec2.options.AWSRunInstancesOptions;
import org.jclouds.aws.ec2.options.RequestSpotInstancesOptions;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.domain.Credentials;
import org.jclouds.ec2.compute.strategy.EC2CreateNodesInGroupThenAddToSet;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.options.RunInstancesOptions;
import org.jclouds.logging.Logger;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
/**
*
* @author Adrian Cole
*/
@Singleton
public class AWSEC2CreateNodesInGroupThenAddToSet extends EC2CreateNodesInGroupThenAddToSet {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
@VisibleForTesting
final AWSEC2Client client;
final SpotInstanceRequestToAWSRunningInstance spotConverter;
@Inject
protected AWSEC2CreateNodesInGroupThenAddToSet(
AWSEC2Client client,
Provider<TemplateBuilder> templateBuilderProvider,
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
AWSEC2InstancePresent instancePresent,
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
Function<RunningInstance, Credentials> instanceToCredentials, Map<String, Credentials> credentialStore,
ComputeUtils utils, SpotInstanceRequestToAWSRunningInstance spotConverter) {
super(client, templateBuilderProvider, createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, instancePresent,
runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils);
this.client = checkNotNull(client, "client");
this.spotConverter = checkNotNull(spotConverter, "spotConverter");
}
protected Iterable<? extends RunningInstance> createNodesInRegionAndZone(String region, String zone, int count,
Template template, RunInstancesOptions instanceOptions) {
Float spotPrice = getSpotPriceOrNull(template.getOptions());
if (spotPrice != null) {
LaunchSpecification spec = AWSRunInstancesOptions.class.cast(instanceOptions).getLaunchSpecificationBuilder()
.imageId(template.getImage().getProviderId()).availabilityZone(zone).build();
RequestSpotInstancesOptions options = AWSEC2TemplateOptions.class.cast(template.getOptions()).getSpotOptions();
if (logger.isDebugEnabled())
logger.debug(">> requesting %d spot instances region(%s) price(%f) spec(%s) options(%s)", count, region,
spotPrice, spec, options);
return Iterables.transform(client.getSpotInstanceServices().requestSpotInstancesInRegion(region, spotPrice,
count, spec, options), spotConverter);
} else {
return super.createNodesInRegionAndZone(zone, zone, count, template, instanceOptions);
}
}
private Float getSpotPriceOrNull(TemplateOptions options) {
return options instanceof AWSEC2TemplateOptions ? AWSEC2TemplateOptions.class.cast(options).getSpotPrice() : null;
}
}

View File

@ -0,0 +1,55 @@
package org.jclouds.aws.ec2.compute.strategy;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.getOnlyElement;
import java.util.Map;
import java.util.NoSuchElementException;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.AWSEC2Client;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.jclouds.domain.Credentials;
import org.jclouds.ec2.compute.strategy.EC2DestroyNodeStrategy;
import com.google.common.collect.Iterables;
/**
*
* @author Adrian Cole
*/
@Singleton
public class AWSEC2DestroyNodeStrategy extends EC2DestroyNodeStrategy {
protected final AWSEC2Client client;
protected final Map<String, Credentials> credentialStore;
@Inject
protected AWSEC2DestroyNodeStrategy(AWSEC2Client client, GetNodeMetadataStrategy getNode,
Map<String, Credentials> credentialStore) {
super(client, getNode);
this.client = checkNotNull(client, "client");
this.credentialStore = checkNotNull(credentialStore, "credentialStore");
}
@Override
protected void destroyInstanceInRegion(String region, String id) {
String spotId = id;
if (id.indexOf("sir-") != 0) {
try {
spotId = getOnlyElement(
Iterables.concat(client.getInstanceServices().describeInstancesInRegion(region, id)))
.getSpotInstanceRequestId();
credentialStore.remove("node#" + region + "/" + spotId);
} catch (NoSuchElementException e) {
}
super.destroyInstanceInRegion(region, id);
} else {
client.getSpotInstanceServices().cancelSpotInstanceRequestsInRegion(region, spotId);
credentialStore.remove("node#" + region + "/" + id);
}
}
}

View File

@ -0,0 +1,68 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.compute.strategy;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.getOnlyElement;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.AWSEC2Client;
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
import org.jclouds.aws.ec2.functions.SpotInstanceRequestToAWSRunningInstance;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.ec2.compute.strategy.EC2GetNodeMetadataStrategy;
import org.jclouds.ec2.domain.RunningInstance;
import com.google.common.base.Function;
/**
*
* @author Adrian Cole
*/
@Singleton
public class AWSEC2GetNodeMetadataStrategy extends EC2GetNodeMetadataStrategy {
private final AWSEC2Client client;
private final SpotInstanceRequestToAWSRunningInstance spotConverter;
@Inject
protected AWSEC2GetNodeMetadataStrategy(AWSEC2Client client,
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
SpotInstanceRequestToAWSRunningInstance spotConverter) {
super(client, runningInstanceToNodeMetadata);
this.client = checkNotNull(client, "client");
this.spotConverter = checkNotNull(spotConverter, "spotConverter");
}
@Override
public RunningInstance getRunningInstanceInRegion(String region, String id) {
if (id.indexOf("sir-") != 0)
return super.getRunningInstanceInRegion(region, id);
SpotInstanceRequest spot = getOnlyElement(client.getSpotInstanceServices().describeSpotInstanceRequestsInRegion(
region, id));
if (spot.getState() == SpotInstanceRequest.State.ACTIVE)
return super.getRunningInstanceInRegion(region, spot.getInstanceId());
else
return spotConverter.apply(spot);
}
}

View File

@ -0,0 +1,85 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.compute.strategy;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.notNull;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
import static org.jclouds.concurrent.FutureIterables.transformParallel;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.aws.ec2.AWSEC2AsyncClient;
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
import org.jclouds.aws.ec2.functions.SpotInstanceRequestToAWSRunningInstance;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.ec2.compute.strategy.EC2ListNodesStrategy;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.location.Region;
import com.google.common.base.Function;
/**
*
* @author Adrian Cole
*/
@Singleton
public class AWSEC2ListNodesStrategy extends EC2ListNodesStrategy {
protected final AWSEC2AsyncClient client;
protected final SpotInstanceRequestToAWSRunningInstance spotConverter;
@Inject
protected AWSEC2ListNodesStrategy(AWSEC2AsyncClient client, @Region Set<String> regions,
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
SpotInstanceRequestToAWSRunningInstance spotConverter) {
super(client, regions, runningInstanceToNodeMetadata, executor);
this.client = checkNotNull(client, "client");
this.spotConverter = checkNotNull(spotConverter, "spotConverter");
}
@Override
protected Iterable<? extends RunningInstance> pollRunningInstances() {
Iterable<? extends AWSRunningInstance> spots = filter(transform(concat(transformParallel(regions,
new Function<String, Future<Set<SpotInstanceRequest>>>() {
@SuppressWarnings("unchecked")
@Override
public Future<Set<SpotInstanceRequest>> apply(String from) {
return (Future<Set<SpotInstanceRequest>>) client.getSpotInstanceServices()
.describeSpotInstanceRequestsInRegion(from);
}
}, executor, null, logger, "reservations")), spotConverter), notNull());
return concat(super.pollRunningInstances(), spots);
}
}

View File

@ -37,6 +37,8 @@ import org.jclouds.aws.ec2.services.MonitoringAsyncClient;
import org.jclouds.aws.ec2.services.MonitoringClient;
import org.jclouds.aws.ec2.services.PlacementGroupAsyncClient;
import org.jclouds.aws.ec2.services.PlacementGroupClient;
import org.jclouds.aws.ec2.services.SpotInstanceAsyncClient;
import org.jclouds.aws.ec2.services.SpotInstanceClient;
import org.jclouds.ec2.EC2AsyncClient;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.config.EC2RestClientModule;
@ -82,6 +84,7 @@ public class AWSEC2RestClientModule extends EC2RestClientModule<AWSEC2Client, AW
.put(WindowsClient.class, WindowsAsyncClient.class)//
.put(AvailabilityZoneAndRegionClient.class, AvailabilityZoneAndRegionAsyncClient.class)//
.put(ElasticBlockStoreClient.class, ElasticBlockStoreAsyncClient.class)//
.put(SpotInstanceClient.class, SpotInstanceAsyncClient.class)//
.build();
public AWSEC2RestClientModule() {

View File

@ -42,6 +42,9 @@ import com.google.common.collect.Sets;
* @author Adrian Cole
*/
public class AWSRunningInstance extends RunningInstance {
public static Builder builder() {
return new Builder();
}
public static class Builder extends org.jclouds.ec2.domain.RunningInstance.Builder {
private MonitoringState monitoringState;

View File

@ -0,0 +1,350 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Arrays;
import java.util.Set;
import javax.annotation.Nullable;
import org.jclouds.ec2.domain.BlockDeviceMapping;
import org.jclouds.ec2.domain.BlockDeviceMapping.MapEBSSnapshotToDevice;
import org.jclouds.ec2.domain.BlockDeviceMapping.MapEphemeralDeviceToDevice;
import org.jclouds.ec2.domain.BlockDeviceMapping.MapNewVolumeToDevice;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
/**
*
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-RequestSpotInstances.html"
* />
* @author Adrian Cole
*/
public class LaunchSpecification {
public static Builder builder() {
return new Builder();
}
public static class Builder {
protected ImmutableSet.Builder<String> groupIds = ImmutableSet.<String> builder();
protected String imageId;
protected String instanceType;
protected String kernelId;
protected String keyName;
protected String availabilityZone;
protected String ramdiskId;
protected Boolean monitoringEnabled;
protected ImmutableSet.Builder<BlockDeviceMapping> blockDeviceMappings = ImmutableSet
.<BlockDeviceMapping> builder();
protected byte[] userData;
public void clear() {
groupIds = ImmutableSet.<String> builder();
imageId = null;
instanceType = null;
kernelId = null;
keyName = null;
availabilityZone = null;
ramdiskId = null;
monitoringEnabled = false;
blockDeviceMappings = ImmutableSet.<BlockDeviceMapping> builder();
userData = null;
}
public Builder groupIds(Iterable<String> groupIds) {
this.groupIds.addAll(checkNotNull(groupIds, "groupIds"));
return this;
}
public Builder groupId(String groupId) {
if (groupId != null)
this.groupIds.add(groupId);
return this;
}
public Builder imageId(String imageId) {
this.imageId = imageId;
return this;
}
public Builder monitoringEnabled(Boolean monitoringEnabled) {
this.monitoringEnabled = monitoringEnabled;
return this;
}
public Builder instanceType(String instanceType) {
this.instanceType = instanceType;
return this;
}
public Builder kernelId(String kernelId) {
this.kernelId = kernelId;
return this;
}
public Builder keyName(String keyName) {
this.keyName = keyName;
return this;
}
public Builder availabilityZone(String availabilityZone) {
this.availabilityZone = availabilityZone;
return this;
}
public Builder ramdiskId(String ramdiskId) {
this.ramdiskId = ramdiskId;
return this;
}
public Builder mapEBSSnapshotToDevice(String deviceName, String snapshotId, @Nullable Integer sizeInGib,
boolean deleteOnTermination) {
blockDeviceMappings.add(new MapEBSSnapshotToDevice(deviceName, snapshotId, sizeInGib, deleteOnTermination));
return this;
}
public Builder mapNewVolumeToDevice(String deviceName, int sizeInGib, boolean deleteOnTermination) {
blockDeviceMappings.add(new MapNewVolumeToDevice(deviceName, sizeInGib, deleteOnTermination));
return this;
}
public Builder mapEphemeralDeviceToDevice(String deviceName, String virtualName) {
blockDeviceMappings.add(new MapEphemeralDeviceToDevice(deviceName, virtualName));
return this;
}
public Builder blockDeviceMapping(BlockDeviceMapping blockDeviceMapping) {
this.blockDeviceMappings.add(checkNotNull(blockDeviceMapping, "blockDeviceMapping"));
return this;
}
public Builder blockDeviceMappings(Iterable<? extends BlockDeviceMapping> blockDeviceMappings) {
this.blockDeviceMappings.addAll(checkNotNull(blockDeviceMappings, "blockDeviceMappings"));
return this;
}
public Builder userData(byte[] userData) {
this.userData = userData;
return this;
}
public LaunchSpecification build() {
return new LaunchSpecification(instanceType, imageId, kernelId, ramdiskId, availabilityZone, keyName,
groupIds.build(), blockDeviceMappings.build(), monitoringEnabled, userData);
}
public static Builder fromLaunchSpecification(LaunchSpecification in) {
return new Builder().instanceType(in.getInstanceType()).imageId(in.getImageId()).kernelId(in.getKernelId())
.ramdiskId(in.getRamdiskId()).availabilityZone(in.getAvailabilityZone()).keyName(in.getKeyName())
.groupIds(in.getGroupIds()).blockDeviceMappings(in.getBlockDeviceMappings())
.monitoringEnabled(in.isMonitoringEnabled()).userData(in.getUserData());
}
}
protected final String instanceType;
protected final String imageId;
protected final String kernelId;
protected final String ramdiskId;
protected final String availabilityZone;
protected final String keyName;
protected final Set<String> groupIds;
protected final Set<? extends BlockDeviceMapping> blockDeviceMappings;
protected final Boolean monitoringEnabled;
protected final byte[] userData;
public LaunchSpecification(String instanceType, String imageId, String kernelId, String ramdiskId,
String availabilityZone, String keyName, Iterable<String> groupIds,
Iterable<? extends BlockDeviceMapping> blockDeviceMappings, Boolean monitoringEnabled, byte[] userData) {
this.instanceType = checkNotNull(instanceType, "instanceType");
this.imageId = checkNotNull(imageId, "imageId");
this.kernelId = kernelId;
this.ramdiskId = ramdiskId;
this.availabilityZone = availabilityZone;
this.keyName = keyName;
this.groupIds = ImmutableSortedSet.copyOf(checkNotNull(groupIds, "groupIds"));
this.blockDeviceMappings = ImmutableSortedSet.copyOf(checkNotNull(blockDeviceMappings, "blockDeviceMappings"));
this.monitoringEnabled = monitoringEnabled;
this.userData = userData;
}
/**
* Image ID of the AMI used to launch the instance.
*/
public String getImageId() {
return imageId;
}
/**
* CloudWatch support
*/
public Boolean isMonitoringEnabled() {
return monitoringEnabled;
}
/**
* The instance type.
*/
public String getInstanceType() {
return instanceType;
}
/**
* Optional. Kernel associated with this instance.
*/
public String getKernelId() {
return kernelId;
}
/**
* If this instance was launched with an associated key pair, this displays the key pair name.
*/
public String getKeyName() {
return keyName;
}
/**
* The location where the instance launched.
*/
public String getAvailabilityZone() {
return availabilityZone;
}
/**
* Optional. RAM disk associated with this instance.
*/
public String getRamdiskId() {
return ramdiskId;
}
/**
* volumes mappings associated with the instance.
*/
public Set<? extends BlockDeviceMapping> getBlockDeviceMappings() {
return blockDeviceMappings;
}
/**
* Names of the security groups.
*/
public Set<String> getGroupIds() {
return groupIds;
}
/**
* User Data
*/
public byte[] getUserData() {
return userData;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((availabilityZone == null) ? 0 : availabilityZone.hashCode());
result = prime * result + ((blockDeviceMappings == null) ? 0 : blockDeviceMappings.hashCode());
result = prime * result + ((groupIds == null) ? 0 : groupIds.hashCode());
result = prime * result + ((imageId == null) ? 0 : imageId.hashCode());
result = prime * result + ((instanceType == null) ? 0 : instanceType.hashCode());
result = prime * result + ((kernelId == null) ? 0 : kernelId.hashCode());
result = prime * result + ((keyName == null) ? 0 : keyName.hashCode());
result = prime * result + ((monitoringEnabled == null) ? 0 : monitoringEnabled.hashCode());
result = prime * result + ((ramdiskId == null) ? 0 : ramdiskId.hashCode());
result = prime * result + Arrays.hashCode(userData);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LaunchSpecification other = (LaunchSpecification) obj;
if (availabilityZone == null) {
if (other.availabilityZone != null)
return false;
} else if (!availabilityZone.equals(other.availabilityZone))
return false;
if (blockDeviceMappings == null) {
if (other.blockDeviceMappings != null)
return false;
} else if (!blockDeviceMappings.equals(other.blockDeviceMappings))
return false;
if (groupIds == null) {
if (other.groupIds != null)
return false;
} else if (!groupIds.equals(other.groupIds))
return false;
if (imageId == null) {
if (other.imageId != null)
return false;
} else if (!imageId.equals(other.imageId))
return false;
if (instanceType == null) {
if (other.instanceType != null)
return false;
} else if (!instanceType.equals(other.instanceType))
return false;
if (kernelId == null) {
if (other.kernelId != null)
return false;
} else if (!kernelId.equals(other.kernelId))
return false;
if (keyName == null) {
if (other.keyName != null)
return false;
} else if (!keyName.equals(other.keyName))
return false;
if (monitoringEnabled == null) {
if (other.monitoringEnabled != null)
return false;
} else if (!monitoringEnabled.equals(other.monitoringEnabled))
return false;
if (ramdiskId == null) {
if (other.ramdiskId != null)
return false;
} else if (!ramdiskId.equals(other.ramdiskId))
return false;
if (!Arrays.equals(userData, other.userData))
return false;
return true;
}
public Builder toBuilder() {
return Builder.fromLaunchSpecification(this);
}
@Override
public String toString() {
return "[instanceType=" + instanceType + ", imageId=" + imageId + ", kernelId=" + kernelId + ", ramdiskId="
+ ramdiskId + ", availabilityZone=" + availabilityZone + ", keyName=" + keyName + ", groupIds=" + groupIds
+ ", blockDeviceMappings=" + blockDeviceMappings + ", monitoringEnabled=" + monitoringEnabled
+ ", userData=" + (userData != null) + "]";
}
}

View File

@ -0,0 +1,173 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Date;
/**
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeSpotPriceHistory.html"
* />
* @author Adrian Cole
*/
public class Spot implements Comparable<Spot> {
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String region;
private String instanceType;
private String productDescription;
private float spotPrice;
private Date timestamp;
public void clear() {
this.region = null;
this.instanceType = null;
this.productDescription = null;
this.spotPrice = 0.0f;
this.timestamp = null;
}
public Builder region(String region) {
this.region = region;
return this;
}
public Builder instanceType(String instanceType) {
this.instanceType = instanceType;
return this;
}
public Builder productDescription(String productDescription) {
this.productDescription = productDescription;
return this;
}
public Builder spotPrice(float spotPrice) {
this.spotPrice = spotPrice;
return this;
}
public Builder timestamp(Date timestamp) {
this.timestamp = timestamp;
return this;
}
public Spot build() {
return new Spot(region, instanceType, productDescription, spotPrice, timestamp);
}
}
private final String region;
private final String instanceType;
private final String productDescription;
private final float spotPrice;
private final Date timestamp;
public Spot(String region, String instanceType, String productDescription, float spotPrice, Date timestamp) {
this.region = checkNotNull(region, "region");
this.instanceType = checkNotNull(instanceType, "instanceType");
this.productDescription = checkNotNull(productDescription, "productDescription");
this.spotPrice = spotPrice;
this.timestamp = checkNotNull(timestamp, "timestamp");
}
public String getRegion() {
return region;
}
public String getInstanceType() {
return instanceType;
}
public String getProductDescription() {
return productDescription;
}
public float getSpotPrice() {
return spotPrice;
}
public Date getTimestamp() {
return timestamp;
}
@Override
public int compareTo(Spot o) {
return Float.compare(spotPrice, o.spotPrice);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((instanceType == null) ? 0 : instanceType.hashCode());
result = prime * result + ((productDescription == null) ? 0 : productDescription.hashCode());
result = prime * result + ((region == null) ? 0 : region.hashCode());
result = prime * result + Float.floatToIntBits(spotPrice);
result = prime * result + ((timestamp == null) ? 0 : timestamp.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Spot other = (Spot) obj;
if (instanceType == null) {
if (other.instanceType != null)
return false;
} else if (!instanceType.equals(other.instanceType))
return false;
if (productDescription == null) {
if (other.productDescription != null)
return false;
} else if (!productDescription.equals(other.productDescription))
return false;
if (region == null) {
if (other.region != null)
return false;
} else if (!region.equals(other.region))
return false;
if (Float.floatToIntBits(spotPrice) != Float.floatToIntBits(other.spotPrice))
return false;
if (timestamp == null) {
if (other.timestamp != null)
return false;
} else if (!timestamp.equals(other.timestamp))
return false;
return true;
}
@Override
public String toString() {
return "[region=" + region + ", instanceType=" + instanceType + ", productDescription=" + productDescription
+ ", spotPrice=" + spotPrice + ", timestamp=" + timestamp + "]";
}
}

View File

@ -0,0 +1,406 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Date;
import com.google.common.base.CaseFormat;
/**
*
* @author Adrian Cole
*/
public class SpotInstanceRequest implements Comparable<SpotInstanceRequest> {
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String region;
private String availabilityZoneGroup;
private Date createTime;
private String faultCode;
private String faultMessage;
private String instanceId;
private String launchGroup;
private LaunchSpecification launchSpecification;
private String productDescription;
private String id;
private float spotPrice;
private State state;
private Type type;
private Date validFrom;
private Date validUntil;
public Builder clear() {
this.region = null;
this.availabilityZoneGroup = null;
this.createTime = null;
this.faultCode = null;
this.faultMessage = null;
this.instanceId = null;
this.launchGroup = null;
this.launchSpecification = null;
this.productDescription = null;
this.id = null;
this.spotPrice = 0;
this.state = null;
this.type = null;
this.validFrom = null;
this.validUntil = null;
return this;
}
public Builder region(String region) {
this.region = region;
return this;
}
public Builder availabilityZoneGroup(String availabilityZoneGroup) {
this.availabilityZoneGroup = availabilityZoneGroup;
return this;
}
public Builder createTime(Date createTime) {
this.createTime = createTime;
return this;
}
public Builder faultCode(String faultCode) {
this.faultCode = faultCode;
return this;
}
public Builder faultMessage(String faultMessage) {
this.faultMessage = faultMessage;
return this;
}
public Builder instanceId(String instanceId) {
this.instanceId = instanceId;
return this;
}
public Builder launchGroup(String launchGroup) {
this.launchGroup = launchGroup;
return this;
}
public Builder launchSpecification(LaunchSpecification launchSpecification) {
this.launchSpecification = launchSpecification;
return this;
}
public Builder productDescription(String productDescription) {
this.productDescription = productDescription;
return this;
}
public Builder id(String id) {
this.id = id;
return this;
}
public Builder spotPrice(float spotPrice) {
this.spotPrice = spotPrice;
return this;
}
public Builder state(State state) {
this.state = state;
return this;
}
public Builder type(Type type) {
this.type = type;
return this;
}
public Builder validFrom(Date validFrom) {
this.validFrom = validFrom;
return this;
}
public Builder validUntil(Date validUntil) {
this.validUntil = validUntil;
return this;
}
public SpotInstanceRequest build() {
return new SpotInstanceRequest(region, availabilityZoneGroup, createTime, faultCode, faultMessage, instanceId,
launchGroup, launchSpecification, productDescription, id, spotPrice, state, type, validFrom, validUntil);
}
}
public enum Type {
ONE_TIME, PERSISTENT, UNRECOGNIZED;
public String value() {
return (CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, name()));
}
@Override
public String toString() {
return value();
}
public static Type fromValue(String type) {
try {
return valueOf(CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, checkNotNull(type, "type")));
} catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
}
public enum State {
OPEN, ACTIVE, CANCELLED, CLOSED, UNRECOGNIZED;
public String value() {
return (CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, name()));
}
@Override
public String toString() {
return value();
}
public static State fromValue(String state) {
try {
return valueOf(CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, checkNotNull(state, "type")));
} catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
}
private final String region;
private final String availabilityZoneGroup;
private final Date createTime;
private final String faultCode;
private final String faultMessage;
private final String instanceId;
private final String launchGroup;
private final LaunchSpecification launchSpecification;
private final String productDescription;
private final String id;
private final float spotPrice;
private final State state;
private final Type type;
private final Date validFrom;
private final Date validUntil;
public SpotInstanceRequest(String region, String availabilityZoneGroup, Date createTime, String faultCode,
String faultMessage, String instanceId, String launchGroup, LaunchSpecification launchSpecification,
String productDescription, String id, float spotPrice, State state, Type type, Date validFrom, Date validUntil) {
this.region = checkNotNull(region, "region");
this.availabilityZoneGroup = availabilityZoneGroup;
this.createTime = createTime;
this.faultCode = faultCode;
this.faultMessage = faultMessage;
this.instanceId = instanceId;
this.launchGroup = launchGroup;
this.launchSpecification = launchSpecification;
this.productDescription = productDescription;
this.id = checkNotNull(id, "id");
this.spotPrice = spotPrice;
this.state = checkNotNull(state, "state");
this.type = checkNotNull(type, "type");
this.validFrom = validFrom;
this.validUntil = validUntil;
}
/**
* @return spot instance requests are in a region
*/
public String getRegion() {
return region;
}
public String getAvailabilityZoneGroup() {
return availabilityZoneGroup;
}
public Date getCreateTime() {
return createTime;
}
public String getFaultCode() {
return faultCode;
}
public String getFaultMessage() {
return faultMessage;
}
public String getInstanceId() {
return instanceId;
}
public String getLaunchGroup() {
return launchGroup;
}
public LaunchSpecification getLaunchSpecification() {
return launchSpecification;
}
public String getProductDescription() {
return productDescription;
}
public String getId() {
return id;
}
public float getSpotPrice() {
return spotPrice;
}
public State getState() {
return state;
}
public Type getType() {
return type;
}
public Date getValidFrom() {
return validFrom;
}
public Date getValidUntil() {
return validUntil;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((availabilityZoneGroup == null) ? 0 : availabilityZoneGroup.hashCode());
result = prime * result + ((createTime == null) ? 0 : createTime.hashCode());
result = prime * result + ((faultCode == null) ? 0 : faultCode.hashCode());
result = prime * result + ((faultMessage == null) ? 0 : faultMessage.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((instanceId == null) ? 0 : instanceId.hashCode());
result = prime * result + ((launchGroup == null) ? 0 : launchGroup.hashCode());
result = prime * result + ((launchSpecification == null) ? 0 : launchSpecification.hashCode());
result = prime * result + ((productDescription == null) ? 0 : productDescription.hashCode());
result = prime * result + ((region == null) ? 0 : region.hashCode());
result = prime * result + Float.floatToIntBits(spotPrice);
result = prime * result + ((type == null) ? 0 : type.hashCode());
result = prime * result + ((validFrom == null) ? 0 : validFrom.hashCode());
result = prime * result + ((validUntil == null) ? 0 : validUntil.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SpotInstanceRequest other = (SpotInstanceRequest) obj;
if (availabilityZoneGroup == null) {
if (other.availabilityZoneGroup != null)
return false;
} else if (!availabilityZoneGroup.equals(other.availabilityZoneGroup))
return false;
if (createTime == null) {
if (other.createTime != null)
return false;
} else if (!createTime.equals(other.createTime))
return false;
if (faultCode == null) {
if (other.faultCode != null)
return false;
} else if (!faultCode.equals(other.faultCode))
return false;
if (faultMessage == null) {
if (other.faultMessage != null)
return false;
} else if (!faultMessage.equals(other.faultMessage))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (instanceId == null) {
if (other.instanceId != null)
return false;
} else if (!instanceId.equals(other.instanceId))
return false;
if (launchGroup == null) {
if (other.launchGroup != null)
return false;
} else if (!launchGroup.equals(other.launchGroup))
return false;
if (launchSpecification == null) {
if (other.launchSpecification != null)
return false;
} else if (!launchSpecification.equals(other.launchSpecification))
return false;
if (productDescription == null) {
if (other.productDescription != null)
return false;
} else if (!productDescription.equals(other.productDescription))
return false;
if (region == null) {
if (other.region != null)
return false;
} else if (!region.equals(other.region))
return false;
if (Float.floatToIntBits(spotPrice) != Float.floatToIntBits(other.spotPrice))
return false;
if (type != other.type)
return false;
if (validFrom == null) {
if (other.validFrom != null)
return false;
} else if (!validFrom.equals(other.validFrom))
return false;
if (validUntil == null) {
if (other.validUntil != null)
return false;
} else if (!validUntil.equals(other.validUntil))
return false;
return true;
}
@Override
public String toString() {
return "[region=" + region + ", id=" + id + ", spotPrice=" + spotPrice + ", state=" + state
+ ", availabilityZoneGroup=" + availabilityZoneGroup + ", createTime=" + createTime + ", faultCode="
+ faultCode + ", type=" + type + ", instanceId=" + instanceId + ", launchGroup=" + launchGroup
+ ", launchSpecification=" + launchSpecification + ", productDescription=" + productDescription
+ ", validFrom=" + validFrom + ", validUntil=" + validUntil + "]";
}
@Override
public int compareTo(SpotInstanceRequest arg0) {
return createTime.compareTo(arg0.createTime);
}
}

View File

@ -0,0 +1,64 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.functions;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
import org.jclouds.aws.ec2.domain.LaunchSpecification;
import org.jclouds.aws.ec2.domain.MonitoringState;
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
import org.jclouds.ec2.domain.InstanceState;
import com.google.common.base.Function;
/**
* @author Adrian Cole
*/
@Singleton
public class SpotInstanceRequestToAWSRunningInstance implements Function<SpotInstanceRequest, AWSRunningInstance> {
@Override
public AWSRunningInstance apply(SpotInstanceRequest request) {
if (request == null)
return null;
if (request.getState() != SpotInstanceRequest.State.OPEN)
return null;
AWSRunningInstance.Builder builder = AWSRunningInstance.builder();
builder.spotInstanceRequestId(request.getId());
builder.instanceId(request.getId());
builder.instanceState(InstanceState.PENDING);
builder.region(request.getRegion());
LaunchSpecification spec = request.getLaunchSpecification();
builder.availabilityZone(spec.getAvailabilityZone());
// TODO convert
// builder.devices(spec.getBlockDeviceMappings());
builder.groupIds(spec.getGroupIds());
builder.imageId(spec.getImageId());
builder.instanceType(spec.getInstanceType());
builder.kernelId(spec.getKernelId());
builder.keyName(spec.getKeyName());
builder.ramdiskId(spec.getRamdiskId());
builder.monitoringState(Boolean.TRUE.equals(spec.isMonitoringEnabled()) ? MonitoringState.PENDING
: MonitoringState.DISABLED);
return builder.build();
}
}

View File

@ -23,10 +23,13 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Set;
import org.jclouds.aws.ec2.domain.LaunchSpecification;
import org.jclouds.ec2.domain.BlockDeviceMapping;
import org.jclouds.ec2.domain.InstanceType;
import org.jclouds.ec2.options.RunInstancesOptions;
import com.google.common.collect.ImmutableSet;
/**
* Contains options supported in the Form API for the RunInstances operation. <h2>
* Usage</h2> The recommended way to instantiate a RunInstancesOptions object is to statically
@ -46,6 +49,7 @@ import org.jclouds.ec2.options.RunInstancesOptions;
* />
*/
public class AWSRunInstancesOptions extends RunInstancesOptions {
private LaunchSpecification.Builder launchSpecificationBuilder = LaunchSpecification.builder();
public static final AWSRunInstancesOptions NONE = new AWSRunInstancesOptions();
/**
@ -60,22 +64,15 @@ public class AWSRunInstancesOptions extends RunInstancesOptions {
return this;
}
String getPlacementGroup() {
return getFirstFormOrNull("Placement.GroupName");
}
/**
* Enables monitoring for the instance.
*/
public AWSRunInstancesOptions enableMonitoring() {
formParameters.put("Monitoring.Enabled", "true");
launchSpecificationBuilder.monitoringEnabled(true);
return this;
}
String getMonitoringEnabled() {
return getFirstFormOrNull("Monitoring.Enabled");
}
/**
* Specifies the subnet ID within which to launch the instance(s) for Amazon Virtual Private
* Cloud.
@ -85,10 +82,6 @@ public class AWSRunInstancesOptions extends RunInstancesOptions {
return this;
}
String getSubnetId() {
return getFirstFormOrNull("SubnetId");
}
public static class Builder extends RunInstancesOptions.Builder {
/**
@ -175,46 +168,63 @@ public class AWSRunInstancesOptions extends RunInstancesOptions {
@Override
public AWSRunInstancesOptions withBlockDeviceMappings(Set<? extends BlockDeviceMapping> mappings) {
launchSpecificationBuilder.blockDeviceMappings(mappings);
return AWSRunInstancesOptions.class.cast(super.withBlockDeviceMappings(mappings));
}
@Override
public AWSRunInstancesOptions withKernelId(String kernelId) {
launchSpecificationBuilder.kernelId(kernelId);
return AWSRunInstancesOptions.class.cast(super.withKernelId(kernelId));
}
@Override
public AWSRunInstancesOptions withKeyName(String keyName) {
launchSpecificationBuilder.keyName(keyName);
return AWSRunInstancesOptions.class.cast(super.withKeyName(keyName));
}
@Override
public AWSRunInstancesOptions withRamdisk(String ramDiskId) {
launchSpecificationBuilder.ramdiskId(ramDiskId);
return AWSRunInstancesOptions.class.cast(super.withRamdisk(ramDiskId));
}
@Override
public AWSRunInstancesOptions withSecurityGroup(String securityGroup) {
launchSpecificationBuilder.groupId(securityGroup);
return AWSRunInstancesOptions.class.cast(super.withSecurityGroup(securityGroup));
}
@Override
public AWSRunInstancesOptions withSecurityGroups(Iterable<String> securityGroups) {
launchSpecificationBuilder.groupIds(securityGroups);
return AWSRunInstancesOptions.class.cast(super.withSecurityGroups(securityGroups));
}
@Override
public AWSRunInstancesOptions withSecurityGroups(String... securityGroups) {
launchSpecificationBuilder.groupIds(ImmutableSet.copyOf(securityGroups));
return AWSRunInstancesOptions.class.cast(super.withSecurityGroups(securityGroups));
}
@Override
public AWSRunInstancesOptions withUserData(byte[] unencodedData) {
launchSpecificationBuilder.userData(unencodedData);
return AWSRunInstancesOptions.class.cast(super.withUserData(unencodedData));
}
@Override
public AWSRunInstancesOptions asType(String type) {
launchSpecificationBuilder.instanceType(type);
return AWSRunInstancesOptions.class.cast(super.asType(type));
}
public synchronized LaunchSpecification.Builder getLaunchSpecificationBuilder() {
try {
return launchSpecificationBuilder.imageId("fake").build().toBuilder().imageId(null);
} finally {
launchSpecificationBuilder.imageId(null);
}
}
}

View File

@ -0,0 +1,119 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.options;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Date;
import org.jclouds.date.DateService;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.ec2.domain.InstanceType;
import org.jclouds.ec2.options.internal.BaseEC2RequestOptions;
/**
* Contains options supported in the Form API for the DescribeSpotPriceHistory operation. <h2>
* Usage</h2> The recommended way to instantiate a DescribeSpotPriceHistoryOptions object is to
* statically import DescribeSpotPriceHistoryOptions.Builder.* and invoke a static creation method
* followed by an instance mutator (if needed):
* <p/>
* <code>
* import static org.jclouds.aws.ec2.options.DescribeSpotPriceHistoryOptions.Builder.*
* <p/>
* AWSEC2Client client = // get connection
* history = client.getSpotInstanceServices().describeSpotPriceHistoryInRegion(from(yesterday).instanceType("m1.small"));
* <code>
*
* @author Adrian Cole
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?ApiReference-form-DescribeSpotPriceHistory.html"
* />
*/
public class DescribeSpotPriceHistoryOptions extends BaseEC2RequestOptions {
public static final DescribeSpotPriceHistoryOptions NONE = new DescribeSpotPriceHistoryOptions();
private static final DateService service = new SimpleDateFormatDateService();
/**
* Start date and time of the Spot Instance price history data.
*/
public DescribeSpotPriceHistoryOptions from(Date start) {
formParameters.put("StartTime", service.iso8601DateFormat(checkNotNull(start, "start")));
return this;
}
/**
* End date and time of the Spot Instance price history data.
*/
public DescribeSpotPriceHistoryOptions to(Date end) {
formParameters.put("EndTime", service.iso8601DateFormat(checkNotNull(end, "end")));
return this;
}
/**
* Specifies the instance type to return.
*/
public DescribeSpotPriceHistoryOptions instanceType(String type) {
formParameters.put("InstanceType.1", checkNotNull(type, "type"));
return this;
}
/**
* The description of the AMI.
*/
public DescribeSpotPriceHistoryOptions productDescription(String description) {
formParameters.put("ProductDescription", checkNotNull(description, "description"));
return this;
}
public static class Builder {
/**
* @see DescribeSpotPriceHistoryOptions#from
*/
public static DescribeSpotPriceHistoryOptions from(Date start) {
DescribeSpotPriceHistoryOptions options = new DescribeSpotPriceHistoryOptions();
return options.from(start);
}
/**
* @see DescribeSpotPriceHistoryOptions#to
*/
public static DescribeSpotPriceHistoryOptions to(Date end) {
DescribeSpotPriceHistoryOptions options = new DescribeSpotPriceHistoryOptions();
return options.to(end);
}
/**
* @see DescribeSpotPriceHistoryOptions#instanceType(InstanceType)
*/
public static DescribeSpotPriceHistoryOptions instanceType(String instanceType) {
DescribeSpotPriceHistoryOptions options = new DescribeSpotPriceHistoryOptions();
return options.instanceType(instanceType);
}
/**
* @see DescribeSpotPriceHistoryOptions#productDescription(String)
*/
public static DescribeSpotPriceHistoryOptions productDescription(String description) {
DescribeSpotPriceHistoryOptions options = new DescribeSpotPriceHistoryOptions();
return options.productDescription(description);
}
}
}

View File

@ -0,0 +1,142 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 validUntil 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.aws.ec2.options;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Date;
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
import org.jclouds.date.DateService;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.ec2.options.internal.BaseEC2RequestOptions;
/**
* Contains options supported in the Form API for the RequestSpotInstances operation. <h2>
* Usage</h2> The recommended way validUntil instantiate a RequestSpotInstancesOptions object is
* validUntil statically import RequestSpotInstancesOptions.Builder.* and invoke a static creation
* method followed by an instance mutator (if needed):
* <p/>
* <code>
* import static org.jclouds.aws.ec2.options.RequestSpotInstancesOptions.Builder.*
* <p/>
* AWSEC2Client client = // get connection
* history = client.getSpotInstanceServices().requestSpotInstancesInRegion("us-east-1",validFrom(yesterday).type("m1.small"));
* <code>
*
* @author Adrian Cole
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?ApiReference-form-RequestSpotInstances.html"
* />
*/
public class RequestSpotInstancesOptions extends BaseEC2RequestOptions {
public static final RequestSpotInstancesOptions NONE = new RequestSpotInstancesOptions();
private static final DateService service = new SimpleDateFormatDateService();
/**
* Start date of the request. If this is a one-time request, the request becomes active at this
* date and time and remains active until all instances launch, the request expires, or the
* request is canceled. If the request is persistent, the request becomes active at this date and
* time and remains active until it expires or is canceled.
*/
public RequestSpotInstancesOptions validFrom(Date start) {
formParameters.put("ValidFrom", service.iso8601DateFormat(checkNotNull(start, "start")));
return this;
}
/**
* End date of the request. If this is a one-time request, the request remains active until all
* instances launch, the request is canceled, or this date is reached. If the request is
* persistent, it remains active until it is canceled or this date and time is reached.
*/
public RequestSpotInstancesOptions validUntil(Date end) {
formParameters.put("ValidUntil", service.iso8601DateFormat(checkNotNull(end, "end")));
return this;
}
/**
* Specifies the Spot Instance type.
*/
public RequestSpotInstancesOptions type(SpotInstanceRequest.Type type) {
formParameters.put("Type", checkNotNull(type, "type").toString());
return this;
}
/**
* Specifies the instance launch group. Launch groups are Spot Instances that launch together and
* terminate together.
*/
public RequestSpotInstancesOptions launchGroup(String launchGroup) {
formParameters.put("LaunchGroup", checkNotNull(launchGroup, "launchGroup"));
return this;
}
/**
* Specifies the Availability Zone group. If you specify the same Availability Zone group for all
* Spot Instance requests, all Spot Instances are launched in the same Availability Zone.
*/
public RequestSpotInstancesOptions availabilityZoneGroup(String availabilityZoneGroup) {
formParameters.put("AvailabilityZoneGroup", checkNotNull(availabilityZoneGroup, "availabilityZoneGroup"));
return this;
}
public static class Builder {
/**
* @see RequestSpotInstancesOptions#validFrom
*/
public static RequestSpotInstancesOptions validFrom(Date start) {
RequestSpotInstancesOptions options = new RequestSpotInstancesOptions();
return options.validFrom(start);
}
/**
* @see RequestSpotInstancesOptions#validUntil
*/
public static RequestSpotInstancesOptions validUntil(Date end) {
RequestSpotInstancesOptions options = new RequestSpotInstancesOptions();
return options.validUntil(end);
}
/**
* @see RequestSpotInstancesOptions#type
*/
public static RequestSpotInstancesOptions type(SpotInstanceRequest.Type type) {
RequestSpotInstancesOptions options = new RequestSpotInstancesOptions();
return options.type(type);
}
/**
* @see RequestSpotInstancesOptions#launchGroup(String)
*/
public static RequestSpotInstancesOptions launchGroup(String launchGroup) {
RequestSpotInstancesOptions options = new RequestSpotInstancesOptions();
return options.launchGroup(launchGroup);
}
/**
* @see RequestSpotInstancesOptions#availabilityZoneGroup
*/
public static RequestSpotInstancesOptions availabilityZoneGroup(String availabilityZoneGroup) {
RequestSpotInstancesOptions options = new RequestSpotInstancesOptions();
return options.availabilityZoneGroup(availabilityZoneGroup);
}
}
}

View File

@ -0,0 +1,78 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.predicates;
import java.util.NoSuchElementException;
import javax.annotation.Resource;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.AWSEC2Client;
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
import org.jclouds.logging.Logger;
import org.jclouds.rest.ResourceNotFoundException;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.inject.Inject;
/**
*
*
* @author Adrian Cole
*/
@Singleton
public class SpotInstanceRequestActive implements Predicate<SpotInstanceRequest> {
private final AWSEC2Client client;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public SpotInstanceRequestActive(AWSEC2Client client) {
this.client = client;
}
public boolean apply(SpotInstanceRequest spot) {
logger.trace("looking for state on spot %s", spot);
try {
spot = refresh(spot);
logger.trace("%s: looking for spot state %s: currently: %s", spot.getId(), SpotInstanceRequest.State.ACTIVE,
spot.getState());
if (spot.getState() == SpotInstanceRequest.State.CANCELLED
|| spot.getState() == SpotInstanceRequest.State.CLOSED)
throw new IllegalStateException(String.format("spot request %s %s", spot.getId(), spot.getState()));
if (spot.getFaultCode() != null)
throw new IllegalStateException(String.format("spot request %s fault code(%s) message(%s)", spot.getId(),
spot.getFaultCode(), spot.getFaultMessage()));
return spot.getState() == SpotInstanceRequest.State.ACTIVE;
} catch (ResourceNotFoundException e) {
return false;
} catch (NoSuchElementException e) {
return false;
}
}
private SpotInstanceRequest refresh(SpotInstanceRequest spot) {
return Iterables.getOnlyElement(client.getSpotInstanceServices().describeSpotInstanceRequestsInRegion(
spot.getRegion(), spot.getId()));
}
}

View File

@ -0,0 +1,128 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.services;
import static org.jclouds.aws.reference.FormParameters.ACTION;
import static org.jclouds.aws.reference.FormParameters.VERSION;
import java.util.Set;
import javax.annotation.Nullable;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import org.jclouds.aws.ec2.AWSEC2AsyncClient;
import org.jclouds.aws.ec2.binders.BindLaunchSpecificationToFormParams;
import org.jclouds.aws.ec2.binders.BindSpotInstanceRequestIdsToIndexedFormParams;
import org.jclouds.aws.ec2.domain.LaunchSpecification;
import org.jclouds.aws.ec2.domain.Spot;
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
import org.jclouds.aws.ec2.options.DescribeSpotPriceHistoryOptions;
import org.jclouds.aws.ec2.options.RequestSpotInstancesOptions;
import org.jclouds.aws.ec2.xml.DescribeSpotPriceHistoryResponseHandler;
import org.jclouds.aws.ec2.xml.SpotInstanceHandler;
import org.jclouds.aws.ec2.xml.SpotInstancesHandler;
import org.jclouds.aws.filters.FormSigner;
import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.EndpointParam;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.FormParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides access to EC2 Spot Instances via their REST API.
* <p/>
*
* @author Adrian Cole
*/
@RequestFilters(FormSigner.class)
@FormParams(keys = VERSION, values = AWSEC2AsyncClient.VERSION)
@VirtualHost
public interface SpotInstanceAsyncClient {
/**
* @see SpotInstanceClient#describeSpotInstanceRequestsInRegion
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "DescribeSpotInstanceRequests")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
@XMLResponseParser(SpotInstancesHandler.class)
ListenableFuture<? extends Set<SpotInstanceRequest>> describeSpotInstanceRequestsInRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
@BinderParam(BindSpotInstanceRequestIdsToIndexedFormParams.class) String... requestIds);
/**
* @see SpotInstanceClient#requestSpotInstanceInRegion
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "RequestSpotInstances")
@XMLResponseParser(SpotInstanceHandler.class)
ListenableFuture<SpotInstanceRequest> requestSpotInstanceInRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
@FormParam("SpotPrice") float spotPrice, @FormParam("LaunchSpecification.ImageId") String imageId,
@FormParam("LaunchSpecification.InstanceType") String instanceType);
/**
* @see SpotInstanceClient#requestSpotInstancesInRegion
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "RequestSpotInstances")
@XMLResponseParser(SpotInstancesHandler.class)
ListenableFuture<? extends Set<SpotInstanceRequest>> requestSpotInstancesInRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
@FormParam("SpotPrice") float spotPrice, @FormParam("InstanceCount") int instanceCount,
@BinderParam(BindLaunchSpecificationToFormParams.class) LaunchSpecification launchSpec,
RequestSpotInstancesOptions... options);
/**
* @see SpotInstanceClient#describeSpotPriceHistoryInRegion
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "DescribeSpotPriceHistory")
@XMLResponseParser(DescribeSpotPriceHistoryResponseHandler.class)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<? extends Set<Spot>> describeSpotPriceHistoryInRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
DescribeSpotPriceHistoryOptions... options);
/**
* @see SpotInstanceClient#cancelSpotInstanceRequestsInRegion
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "CancelSpotInstanceRequests")
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
ListenableFuture<Void> cancelSpotInstanceRequestsInRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
@BinderParam(BindSpotInstanceRequestIdsToIndexedFormParams.class) String... requestIds);
}

View File

@ -0,0 +1,159 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.services;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import org.jclouds.aws.ec2.domain.LaunchSpecification;
import org.jclouds.aws.ec2.domain.Spot;
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
import org.jclouds.aws.ec2.options.DescribeSpotPriceHistoryOptions;
import org.jclouds.aws.ec2.options.RequestSpotInstancesOptions;
import org.jclouds.concurrent.Timeout;
/**
* Provides Spot Instance services for EC2. For more information, refer to the Amazon EC2 Developer
* Guide.
* <p/>
*
* @author Adrian Cole
*/
@Timeout(duration = 45, timeUnit = TimeUnit.SECONDS)
public interface SpotInstanceClient {
/**
* Describes Spot Instance requests. Spot Instances are instances that Amazon EC2 starts on your
* behalf when the maximum price that you specify exceeds the current Spot Price. Amazon EC2
* periodically sets the Spot Price based on available Spot Instance capacity and current spot
* instance requests. For conceptual information about Spot Instances, refer to the Amazon
* Elastic Compute Cloud Developer Guide or Amazon Elastic Compute Cloud User Guide.
*
* @param region
* Region where the spot instance service is running
* @param requestIds
* Specifies the ID of the Spot Instance request.
*
* @see #requestSpotInstancesInRegion
* @see #cancelSpotInstanceRequestsInRegion
* @see #describeSpotPriceHistoryInRegion
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeSpotInstanceRequests.html"
* />
* @return TODO
*/
Set<SpotInstanceRequest> describeSpotInstanceRequestsInRegion(@Nullable String region, String... requestIds);
/**
* request a single spot instance
*
* @param region
* Region where the spot instance service is running
* @param spotPrice
* Specifies the maximum hourly price for any Spot Instance launched to fulfill the
* request.
* @param imageId
* The AMI ID.
* @param instanceType
* The instance type (ex. m1.small)
* @return spot instance request
* @see #requestSpotInstancesInRegion
*/
SpotInstanceRequest requestSpotInstanceInRegion(@Nullable String region, float spotPrice, String imageId,
String instanceType);
/**
* Creates a Spot Instance request. Spot Instances are instances that Amazon EC2 starts on your
* behalf when the maximum price that you specify exceeds the current Spot Price. Amazon EC2
* periodically sets the Spot Price based on available Spot Instance capacity and current spot
* instance requests. For conceptual information about Spot Instances, refer to the Amazon
* Elastic Compute Cloud Developer Guide or Amazon Elastic Compute Cloud User Guide.
*
* @param region
* Region where the spot instance service is running
* @param spotPrice
* Specifies the maximum hourly price for any Spot Instance launched to fulfill the
* request.
* @param instanceCount
* number of instances to request
* @param launchSpec
* includes at least The AMI ID and instance type (ex. m1.small)
* @param options
* options including expiration time or grouping
*
* @see #describeSpotInstanceRequestsInRegion
* @see #cancelSpotInstanceRequestsInRegion
* @see #describeSpotPriceHistoryInRegion
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-RequestSpotInstances.html"
* />
* @return set of spot instance requests
*/
Set<SpotInstanceRequest> requestSpotInstancesInRegion(@Nullable String region, float spotPrice, int instanceCount,
LaunchSpecification launchSpec, RequestSpotInstancesOptions... options);
/**
*
* Describes Spot Price history. Spot Instances are instances that Amazon EC2 starts on your
* behalf when the maximum price that you specify exceeds the current Spot Price. Amazon EC2
* periodically sets the Spot Price based on available Spot Instance capacity and current spot
* instance requests. For conceptual information about Spot Instances, refer to the Amazon
* Elastic Compute Cloud Developer Guide or Amazon Elastic Compute Cloud User Guide.
*
* @param region
* Region where the spot instance service is running
* @param options
* options to control the list
*
* @see #describeSpotInstanceRequestsInRegion
* @see #requestSpotInstancesInRegion
* @see #cancelSpotInstanceRequestsInRegion
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeSpotInstanceRequests.html"
* />
* @return TODO
*/
@Timeout(duration = 2, timeUnit = TimeUnit.MINUTES)
Set<Spot> describeSpotPriceHistoryInRegion(@Nullable String region, DescribeSpotPriceHistoryOptions... options);
/**
* Cancels one or more Spot Instance requests. Spot Instances are instances that Amazon EC2
* starts on your behalf when the maximum price that you specify exceeds the current Spot Price.
* Amazon EC2 periodically sets the Spot Price based on available Spot Instance capacity and
* current spot instance requests. For conceptual information about Spot Instances, refer to the
* Amazon Elastic Compute Cloud Developer Guide or Amazon Elastic Compute Cloud User Guide.
*
* @param region
* Region where the spot instance service is running
* @param requestIds
* Specifies the ID of the Spot Instance request.
*
* @see #describeSpotInstanceRequestsInRegion
* @see #requestSpotInstancesInRegion
* @see #describeSpotPriceHistoryInRegion
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-CancelSpotInstanceRequests.html"
* />
* @return TODO
*/
String cancelSpotInstanceRequestsInRegion(@Nullable String region, String... requestIds);
}

View File

@ -0,0 +1,79 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.xml;
import java.util.Set;
import javax.inject.Inject;
import org.jclouds.aws.ec2.domain.Spot;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ParseSax.HandlerWithResult;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
/**
* @author Adrian Cole
*/
public class DescribeSpotPriceHistoryResponseHandler extends
ParseSax.HandlerWithResult<Set<Spot>> {
private Builder<Spot> spots = ImmutableSet.<Spot>builder();
private final SpotHandler spotHandler;
@Inject
public DescribeSpotPriceHistoryResponseHandler(SpotHandler spotHandler) {
this.spotHandler = spotHandler;
}
public Set<Spot> getResult() {
return spots.build();
}
@Override
public HandlerWithResult<Set<Spot>> setContext(HttpRequest request) {
spotHandler.setContext(request);
return super.setContext(request);
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if (!qName.equals("item"))
spotHandler.startElement(uri, localName, qName, attributes);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equals("item")) {
spots.add(spotHandler.getResult());
}
spotHandler.endElement(uri, localName, qName);
}
public void characters(char ch[], int start, int length) {
spotHandler.characters(ch, start, length);
}
}

View File

@ -0,0 +1,115 @@
package org.jclouds.aws.ec2.xml;
import javax.annotation.Resource;
import javax.inject.Inject;
import org.jclouds.aws.ec2.domain.LaunchSpecification;
import org.jclouds.aws.ec2.domain.LaunchSpecification.Builder;
import org.jclouds.date.DateService;
import org.jclouds.ec2.domain.BlockDeviceMapping;
import org.jclouds.http.functions.ParseSax.HandlerForGeneratedRequestWithResult;
import org.jclouds.location.Region;
import org.jclouds.logging.Logger;
import org.xml.sax.Attributes;
/**
*
* @author Adrian Cole
*/
public class LaunchSpecificationHandler extends HandlerForGeneratedRequestWithResult<LaunchSpecification> {
@Resource
protected Logger logger = Logger.NULL;
protected final DateService dateService;
protected final String defaultRegion;
protected final Builder builder;
protected final BlockDeviceMapping.Builder blockDeviceMappingBuilder;
@Inject
public LaunchSpecificationHandler(DateService dateService, @Region String defaultRegion,
LaunchSpecification.Builder builder, BlockDeviceMapping.Builder blockDeviceMappingBuilder) {
this.dateService = dateService;
this.defaultRegion = defaultRegion;
this.builder = builder;
this.blockDeviceMappingBuilder = blockDeviceMappingBuilder;
}
protected String currentOrNull() {
String returnVal = currentText.toString().trim();
return returnVal.equals("") ? null : returnVal;
}
protected StringBuilder currentText = new StringBuilder();
private boolean inBlockDeviceMapping;
public void startElement(String uri, String name, String qName, Attributes attrs) {
if (qName.equals("blockDeviceMapping")) {
inBlockDeviceMapping = true;
}
}
public void endElement(String uri, String name, String qName) {
if (qName.equals("blockDeviceMapping")) {
inBlockDeviceMapping = false;
} else if (qName.equals("item") && inBlockDeviceMapping) {
try {
builder.blockDeviceMapping(blockDeviceMappingBuilder.build());
} finally {
blockDeviceMappingBuilder.clear();
}
} else if (qName.equals("deviceName")) {
blockDeviceMappingBuilder.deviceName(currentOrNull());
} else if (qName.equals("virtualName")) {
blockDeviceMappingBuilder.virtualName(currentOrNull());
} else if (qName.equals("snapshotId")) {
blockDeviceMappingBuilder.snapshotId(currentOrNull());
} else if (qName.equals("volumeSize")) {
String volumeSize = currentOrNull();
if (volumeSize != null)
blockDeviceMappingBuilder.sizeInGib(Integer.parseInt(volumeSize));
} else if (qName.equals("noDevice")) {
String noDevice = currentOrNull();
if (noDevice != null)
blockDeviceMappingBuilder.noDevice(Boolean.parseBoolean(noDevice));
} else if (qName.equals("deleteOnTermination")) {
String deleteOnTermination = currentOrNull();
if (deleteOnTermination != null)
blockDeviceMappingBuilder.deleteOnTermination(Boolean.parseBoolean(deleteOnTermination));
} else if (qName.equals("groupId")) {
builder.groupId(currentOrNull());
} else if (qName.equals("imageId")) {
builder.imageId(currentOrNull());
} else if (qName.equals("instanceType")) {
builder.instanceType(currentOrNull());
} else if (qName.equals("kernelId")) {
builder.kernelId(currentOrNull());
} else if (qName.equals("keyName")) {
builder.keyName(currentOrNull());
} else if (qName.equals("availabilityZone")) {
builder.availabilityZone(currentOrNull());
} else if (qName.equals("ramdiskId")) {
builder.ramdiskId(currentOrNull());
} else if (qName.equals("enabled")) {
String monitoringEnabled = currentOrNull();
if (monitoringEnabled != null)
builder.monitoringEnabled(new Boolean(monitoringEnabled));
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
@Override
public LaunchSpecification getResult() {
try {
return builder.build();
} finally {
builder.clear();
}
}
}

View File

@ -24,7 +24,6 @@ import javax.inject.Inject;
import org.jclouds.aws.ec2.domain.PlacementGroup;
import org.jclouds.aws.ec2.domain.PlacementGroup.State;
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.date.DateService;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.location.Region;
@ -36,8 +35,6 @@ public class PlacementGroupHandler extends
ParseSax.HandlerForGeneratedRequestWithResult<PlacementGroup> {
private StringBuilder currentText = new StringBuilder();
@Inject
protected DateService dateService;
@Inject
@Region
String defaultRegion;

View File

@ -0,0 +1,75 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.xml;
import javax.inject.Inject;
import org.jclouds.aws.ec2.domain.Spot;
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.date.DateService;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.location.Region;
/**
*
* @author Adrian Cole
*/
public class SpotHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Spot> {
private StringBuilder currentText = new StringBuilder();
protected final DateService dateService;
protected final String defaultRegion;
@Inject
public SpotHandler(DateService dateService, @Region String defaultRegion) {
this.dateService = dateService;
this.defaultRegion = defaultRegion;
}
private Spot.Builder builder = Spot.builder();
public Spot getResult() {
try {
String region = getRequest() == null ? null : AWSUtils.findRegionInArgsOrNull(getRequest());
if (region == null)
region = defaultRegion;
return builder.region(region).build();
} finally {
builder.clear();
}
}
public void endElement(String uri, String name, String qName) {
if (qName.equals("instanceType")) {
builder.instanceType(currentText.toString().trim());
} else if (qName.equals("productDescription")) {
builder.productDescription(currentText.toString().trim());
} else if (qName.equals("spotPrice")) {
builder.spotPrice(Float.parseFloat(currentText.toString().trim()));
} else if (qName.equals("timestamp")) {
builder.timestamp(dateService.iso8601DateParse(currentText.toString().trim()));
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -0,0 +1,125 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.xml;
import javax.inject.Inject;
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
import org.jclouds.aws.ec2.domain.SpotInstanceRequest.Builder;
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.date.DateService;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.location.Region;
import org.xml.sax.Attributes;
/**
*
* @author Adrian Cole
*/
public class SpotInstanceHandler extends ParseSax.HandlerForGeneratedRequestWithResult<SpotInstanceRequest> {
private StringBuilder currentText = new StringBuilder();
protected final DateService dateService;
protected final String defaultRegion;
protected final Builder builder;
protected boolean inLaunchSpecification;
protected final LaunchSpecificationHandler launchSpecificationHandler;
@Inject
public SpotInstanceHandler(DateService dateService, @Region String defaultRegion,
LaunchSpecificationHandler launchSpecificationHandler, SpotInstanceRequest.Builder builder) {
this.dateService = dateService;
this.defaultRegion = defaultRegion;
this.launchSpecificationHandler = launchSpecificationHandler;
this.builder = builder;
}
protected String currentOrNull() {
String returnVal = currentText.toString().trim();
return returnVal.equals("") ? null : returnVal;
}
public SpotInstanceRequest getResult() {
try {
String region = getRequest() != null ? AWSUtils.findRegionInArgsOrNull(getRequest()) : null;
if (region == null)
region = defaultRegion;
return builder.region(region).build();
} finally {
builder.clear();
}
}
public void startElement(String uri, String name, String qName, Attributes attrs) {
if (qName.equals("launchSpecification")) {
inLaunchSpecification = true;
}
if (inLaunchSpecification)
launchSpecificationHandler.startElement(uri, name, qName, attrs);
}
public void endElement(String uri, String name, String qName) {
if (qName.equals("launchSpecification")) {
inLaunchSpecification = false;
builder.launchSpecification(launchSpecificationHandler.getResult());
}
if (inLaunchSpecification) {
launchSpecificationHandler.endElement(uri, name, qName);
} else if (qName.equals("spotInstanceRequestId")) {
builder.id(currentOrNull());
} else if (qName.equals("instanceId")) {
builder.instanceId(currentOrNull());
} else if (qName.equals("availabilityZoneGroup")) {
builder.availabilityZoneGroup(currentOrNull());
} else if (qName.equals("launchGroup")) {
builder.launchGroup(currentOrNull());
} else if (qName.equals("code")) {
builder.faultCode(currentOrNull());
} else if (qName.equals("message")) {
builder.faultMessage(currentOrNull());
} else if (qName.equals("spotPrice")) {
String price = currentOrNull();
if (price != null)
builder.spotPrice(Float.parseFloat(price));
} else if (qName.equals("type")) {
String type = currentOrNull();
if (type != null)
builder.type(SpotInstanceRequest.Type.fromValue(type));
} else if (qName.equals("state")) {
String state = currentOrNull();
if (state != null)
builder.state(SpotInstanceRequest.State.fromValue(state));
} else if (qName.equals("createTime")) {
String createTime = currentOrNull();
if (createTime != null)
builder.createTime(dateService.iso8601DateParse(createTime));
} else if (qName.equals("productDescription")) {
builder.productDescription(currentOrNull());
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
if (inLaunchSpecification)
launchSpecificationHandler.characters(ch, start, length);
else
currentText.append(ch, start, length);
}
}

View File

@ -0,0 +1,84 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.xml;
import java.util.Set;
import javax.inject.Inject;
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ParseSax.HandlerWithResult;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
/**
* @author Adrian Cole
*/
public class SpotInstancesHandler extends ParseSax.HandlerWithResult<Set<SpotInstanceRequest>> {
private final Builder<SpotInstanceRequest> spotRequests = ImmutableSet.<SpotInstanceRequest> builder();
private final SpotInstanceHandler spotRequestHandler;
private int itemDepth;
@Inject
public SpotInstancesHandler(SpotInstanceHandler spotRequestHandler) {
this.spotRequestHandler = spotRequestHandler;
}
public Set<SpotInstanceRequest> getResult() {
return spotRequests.build();
}
@Override
public HandlerWithResult<Set<SpotInstanceRequest>> setContext(HttpRequest request) {
spotRequestHandler.setContext(request);
return super.setContext(request);
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (qName.equals("item"))
itemDepth++;
if (itemDepth >= 1)
spotRequestHandler.startElement(uri, localName, qName, attributes);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equals("item") && itemDepth == 1) {
spotRequests.add(spotRequestHandler.getResult());
}
if (qName.equals("item"))
itemDepth--;
if (itemDepth >= 1)
spotRequestHandler.endElement(uri, localName, qName);
}
public void characters(char ch[], int start, int length) {
if (itemDepth >= 1)
spotRequestHandler.characters(ch, start, length);
}
}

View File

@ -0,0 +1,60 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.binders;
import static org.testng.Assert.assertEquals;
import java.net.UnknownHostException;
import org.jclouds.aws.ec2.domain.LaunchSpecification;
import org.jclouds.ec2.domain.InstanceType;
import org.jclouds.encryption.internal.Base64;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
/**
* @author Adrian Cole
*/
@Test(groups = "unit")
public class BindLaunchSpecificationToFormParamsTest {
BindLaunchSpecificationToFormParams binder = new BindLaunchSpecificationToFormParams();
@Test
public void testApplyWithBlockDeviceMappings() throws UnknownHostException {
LaunchSpecification spec = LaunchSpecification.builder().instanceType(InstanceType.T1_MICRO).imageId("ami-123")
.mapNewVolumeToDevice("/dev/sda1", 120, true).build();
assertEquals(binder.apply(spec), ImmutableMap.of("LaunchSpecification.InstanceType", "t1.micro",
"LaunchSpecification.ImageId", "ami-123", "LaunchSpecification.BlockDeviceMapping.1.DeviceName",
"/dev/sda1", "LaunchSpecification.BlockDeviceMapping.1.Ebs.VolumeSize", "120",
"LaunchSpecification.BlockDeviceMapping.1.Ebs.DeleteOnTermination", "true"));
}
@Test
public void testApplyWithUserData() throws UnknownHostException {
LaunchSpecification spec = LaunchSpecification.builder().instanceType(InstanceType.T1_MICRO).imageId("ami-123")
.userData("hello".getBytes()).build();
assertEquals(binder.apply(spec), ImmutableMap.of("LaunchSpecification.InstanceType", "t1.micro",
"LaunchSpecification.ImageId", "ami-123", "LaunchSpecification.UserData",
Base64.encodeBytes("hello".getBytes())));
}
}

View File

@ -59,13 +59,13 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
@Test(enabled = true, dependsOnMethods = "testCompareSizes")
public void testExtendedOptionsAndLogin() throws Exception {
SecurityGroupClient securityGroupClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi())
.getSecurityGroupServices();
.getSecurityGroupServices();
KeyPairClient keyPairClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi())
.getKeyPairServices();
.getKeyPairServices();
InstanceClient instanceClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi())
.getInstanceServices();
.getInstanceServices();
String group = this.group + "o";
@ -76,6 +76,7 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
options.as(AWSEC2TemplateOptions.class).securityGroups(group);
options.as(AWSEC2TemplateOptions.class).keyPair(group);
options.as(AWSEC2TemplateOptions.class).enableMonitoring();
options.as(AWSEC2TemplateOptions.class).spotPrice(0.3f);
String startedId = null;
try {
@ -117,17 +118,17 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
// }
// make sure we made our dummy group and also let in the user's group
assertEquals(Sets.newTreeSet(instance.getGroupIds()),
ImmutableSortedSet.<String> of("jclouds#" + group + "#" + instance.getRegion(), group));
assertEquals(Sets.newTreeSet(instance.getGroupIds()), ImmutableSortedSet.<String> of("jclouds#" + group + "#"
+ instance.getRegion(), group));
// make sure our dummy group has no rules
SecurityGroup secgroup = Iterables.getOnlyElement(securityGroupClient.describeSecurityGroupsInRegion(null,
"jclouds#" + group + "#" + instance.getRegion()));
"jclouds#" + group + "#" + instance.getRegion()));
assert secgroup.getIpPermissions().size() == 0 : secgroup;
// try to run a script with the original keyPair
runScriptWithCreds(group, first.getOperatingSystem(),
new Credentials(first.getCredentials().identity, result.getKeyMaterial()));
runScriptWithCreds(group, first.getOperatingSystem(), new Credentials(first.getCredentials().identity, result
.getKeyMaterial()));
} finally {
client.destroyNodesMatching(NodePredicates.inGroup(group));
@ -151,13 +152,13 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
}
InstanceClient instanceClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi())
.getInstanceServices();
.getInstanceServices();
String group = this.group + "g";
TemplateOptions options = client.templateOptions();
options.as(AWSEC2TemplateOptions.class).subnetId(subnetId);
options.as(AWSEC2TemplateOptions.class).subnetId(subnetId).spotPrice(0.3f);
String startedId = null;
String nodeId = null;

View File

@ -0,0 +1,74 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. .info@cloudconscious.com("
*
* ====================================================================
* Licensed 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.aws.ec2.functions;
import static org.testng.Assert.assertEquals;
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
import org.jclouds.aws.ec2.domain.LaunchSpecification;
import org.jclouds.aws.ec2.domain.MonitoringState;
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
import org.jclouds.aws.ec2.functions.SpotInstanceRequestToAWSRunningInstance;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.ec2.domain.InstanceState;
import org.testng.annotations.Test;
/**
* Tests behavior of {@code SpotInstanceRequestToAWSRunningInstance}
*
* @author Adrian Cole
*/
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "SpotInstanceRequestToAWSRunningInstanceTest")
public class SpotInstanceRequestToAWSRunningInstanceTest {
public void testConvert() {
SpotInstanceRequest input = SpotInstanceRequest.builder().region("us-east-1").id("sir-228e6406")
.spotPrice(0.001f).type(SpotInstanceRequest.Type.ONE_TIME).state(SpotInstanceRequest.State.OPEN)
.launchSpecification(
LaunchSpecification.builder().imageId("ami-595a0a1c").groupId("default").instanceType(
"m1.large").mapNewVolumeToDevice("/dev/sda1", 1, true).mapEBSSnapshotToDevice(
"/dev/sda2", "snap-1ea27576", 1, true).mapEphemeralDeviceToDevice("/dev/sda3", "vre1")
.monitoringEnabled(false).build()).createTime(
new SimpleDateFormatDateService().iso8601DateParse("2011-03-08T03:30:36.000Z"))
.productDescription("Linux/UNIX").build();
assertEquals(new SpotInstanceRequestToAWSRunningInstance().apply(input), AWSRunningInstance.builder().region(
"us-east-1").instanceId("sir-228e6406").spotInstanceRequestId("sir-228e6406").instanceState(
InstanceState.PENDING).imageId("ami-595a0a1c").groupId("default").instanceType("m1.large")
.monitoringState(MonitoringState.PENDING).build());
}
public void testConvertWhenNotOpenReturnsNull() {
assertEquals(new SpotInstanceRequestToAWSRunningInstance().apply(SpotInstanceRequest.builder()
.region("us-east-1").id("sir-228e6406").type(SpotInstanceRequest.Type.ONE_TIME).state(
SpotInstanceRequest.State.ACTIVE).build()), null);
assertEquals(new SpotInstanceRequestToAWSRunningInstance().apply(SpotInstanceRequest.builder()
.region("us-east-1").id("sir-228e6406").type(SpotInstanceRequest.Type.ONE_TIME).state(
SpotInstanceRequest.State.CANCELLED).build()), null);
assertEquals(new SpotInstanceRequestToAWSRunningInstance().apply(SpotInstanceRequest.builder()
.region("us-east-1").id("sir-228e6406").type(SpotInstanceRequest.Type.ONE_TIME).state(
SpotInstanceRequest.State.UNRECOGNIZED).build()), null);
}
}

View File

@ -0,0 +1,122 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.options;
import static org.jclouds.aws.ec2.options.DescribeSpotPriceHistoryOptions.Builder.from;
import static org.jclouds.aws.ec2.options.DescribeSpotPriceHistoryOptions.Builder.instanceType;
import static org.jclouds.aws.ec2.options.DescribeSpotPriceHistoryOptions.Builder.productDescription;
import static org.jclouds.aws.ec2.options.DescribeSpotPriceHistoryOptions.Builder.to;
import static org.testng.Assert.assertEquals;
import java.util.Collections;
import java.util.Date;
import org.jclouds.http.options.HttpRequestOptions;
import org.testng.annotations.Test;
/**
* Tests possible uses of DescribeSpotPriceHistoryOptions and
* DescribeSpotPriceHistoryOptions.Builder.*
*
* @author Adrian Cole
*/
public class DescribeSpotPriceHistoryOptionsTest {
@Test
public void testAssignability() {
assert HttpRequestOptions.class.isAssignableFrom(DescribeSpotPriceHistoryOptions.class);
assert !String.class.isAssignableFrom(DescribeSpotPriceHistoryOptions.class);
}
@Test
public void testDescription() {
DescribeSpotPriceHistoryOptions options = new DescribeSpotPriceHistoryOptions();
options.productDescription("test");
assertEquals(options.buildFormParameters().get("ProductDescription"), Collections.singletonList("test"));
}
@Test
public void testDescriptionStatic() {
DescribeSpotPriceHistoryOptions options = productDescription("test");
assertEquals(options.buildFormParameters().get("ProductDescription"), Collections.singletonList("test"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testDescriptionNPE() {
productDescription(null);
}
@Test
public void testInstanceType() {
DescribeSpotPriceHistoryOptions options = new DescribeSpotPriceHistoryOptions();
options.instanceType("test");
assertEquals(options.buildFormParameters().get("InstanceType.1"), Collections.singletonList("test"));
}
@Test
public void testInstanceTypeStatic() {
DescribeSpotPriceHistoryOptions options = instanceType("test");
assertEquals(options.buildFormParameters().get("InstanceType.1"), Collections.singletonList("test"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testInstanceTypeNPE() {
instanceType(null);
}
@Test
public void testFrom() {
DescribeSpotPriceHistoryOptions options = new DescribeSpotPriceHistoryOptions();
options.from(test);
assertEquals(options.buildFormParameters().get("StartTime"), Collections.singletonList("1970-05-23T21:21:18.910Z"));
}
Date test = new Date(12345678910l);
@Test
public void testFromStatic() {
DescribeSpotPriceHistoryOptions options = from(test);
assertEquals(options.buildFormParameters().get("StartTime"), Collections.singletonList("1970-05-23T21:21:18.910Z"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testFromNPE() {
from(null);
}
@Test
public void testTo() {
DescribeSpotPriceHistoryOptions options = new DescribeSpotPriceHistoryOptions();
options.to(test);
assertEquals(options.buildFormParameters().get("EndTime"), Collections.singletonList("1970-05-23T21:21:18.910Z"));
}
@Test
public void testToStatic() {
DescribeSpotPriceHistoryOptions options = to(test);
assertEquals(options.buildFormParameters().get("EndTime"), Collections.singletonList("1970-05-23T21:21:18.910Z"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testToNPE() {
to(null);
}
}

View File

@ -0,0 +1,145 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 validUntil 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.aws.ec2.options;
import static org.jclouds.aws.ec2.options.RequestSpotInstancesOptions.Builder.availabilityZoneGroup;
import static org.jclouds.aws.ec2.options.RequestSpotInstancesOptions.Builder.launchGroup;
import static org.jclouds.aws.ec2.options.RequestSpotInstancesOptions.Builder.type;
import static org.jclouds.aws.ec2.options.RequestSpotInstancesOptions.Builder.validFrom;
import static org.jclouds.aws.ec2.options.RequestSpotInstancesOptions.Builder.validUntil;
import static org.testng.Assert.assertEquals;
import java.util.Collections;
import java.util.Date;
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
import org.jclouds.http.options.HttpRequestOptions;
import org.testng.annotations.Test;
/**
* Tests possible uses of RequestSpotInstancesOptions and RequestSpotInstancesOptions.Builder.*
*
* @author Adrian Cole
*/
public class RequestSpotInstancesOptionsTest {
@Test
public void testAssignability() {
assert HttpRequestOptions.class.isAssignableFrom(RequestSpotInstancesOptions.class);
assert !String.class.isAssignableFrom(RequestSpotInstancesOptions.class);
}
@Test
public void testAvailabilityZoneGroup() {
RequestSpotInstancesOptions options = new RequestSpotInstancesOptions();
options.availabilityZoneGroup("test");
assertEquals(options.buildFormParameters().get("AvailabilityZoneGroup"), Collections.singletonList("test"));
}
@Test
public void testAvailabilityZoneGroupStatic() {
RequestSpotInstancesOptions options = availabilityZoneGroup("test");
assertEquals(options.buildFormParameters().get("AvailabilityZoneGroup"), Collections.singletonList("test"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testAvailabilityZoneGroupNPE() {
availabilityZoneGroup(null);
}
@Test
public void testLaunchGroup() {
RequestSpotInstancesOptions options = new RequestSpotInstancesOptions();
options.launchGroup("test");
assertEquals(options.buildFormParameters().get("LaunchGroup"), Collections.singletonList("test"));
}
@Test
public void testLaunchGroupStatic() {
RequestSpotInstancesOptions options = launchGroup("test");
assertEquals(options.buildFormParameters().get("LaunchGroup"), Collections.singletonList("test"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testLaunchGroupNPE() {
launchGroup(null);
}
@Test
public void testInstanceType() {
RequestSpotInstancesOptions options = new RequestSpotInstancesOptions();
options.type(SpotInstanceRequest.Type.PERSISTENT);
assertEquals(options.buildFormParameters().get("Type"), Collections.singletonList("persistent"));
}
@Test
public void testInstanceTypeStatic() {
RequestSpotInstancesOptions options = type(SpotInstanceRequest.Type.PERSISTENT);
assertEquals(options.buildFormParameters().get("Type"), Collections.singletonList("persistent"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testInstanceTypeNPE() {
type(null);
}
@Test
public void testFrom() {
RequestSpotInstancesOptions options = new RequestSpotInstancesOptions();
options.validFrom(test);
assertEquals(options.buildFormParameters().get("ValidFrom"),
Collections.singletonList("1970-05-23T21:21:18.910Z"));
}
Date test = new Date(12345678910l);
@Test
public void testFromStatic() {
RequestSpotInstancesOptions options = validFrom(test);
assertEquals(options.buildFormParameters().get("ValidFrom"),
Collections.singletonList("1970-05-23T21:21:18.910Z"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testFromNPE() {
validFrom(null);
}
@Test
public void testTo() {
RequestSpotInstancesOptions options = new RequestSpotInstancesOptions();
options.validUntil(test);
assertEquals(options.buildFormParameters().get("ValidUntil"),
Collections.singletonList("1970-05-23T21:21:18.910Z"));
}
@Test
public void testToStatic() {
RequestSpotInstancesOptions options = validUntil(test);
assertEquals(options.buildFormParameters().get("ValidUntil"),
Collections.singletonList("1970-05-23T21:21:18.910Z"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testToNPE() {
validUntil(null);
}
}

View File

@ -100,7 +100,7 @@ public class AMIClientLiveTest {
setupCredentials();
Properties overrides = setupProperties();
context = new ComputeServiceContextFactory().createContext(provider,
ImmutableSet.<Module> of(new Log4JLoggingModule()), overrides).getProviderSpecificContext();
ImmutableSet.<Module> of(new Log4JLoggingModule()), overrides).getProviderSpecificContext();
client = context.getApi().getAMIServices();
}
@ -135,7 +135,7 @@ public class AMIClientLiveTest {
String imageRegisteredId = client.registerImageFromManifestInRegion(null, "jcloudstest1", DEFAULT_MANIFEST);
imagesToDeregister.add(imageRegisteredId);
Image imageRegisteredFromManifest = Iterables.getOnlyElement(client.describeImagesInRegion(null,
imageIds(imageRegisteredId)));
imageIds(imageRegisteredId)));
assertEquals(imageRegisteredFromManifest.getName(), "jcloudstest1");
assertEquals(imageRegisteredFromManifest.getImageLocation(), DEFAULT_MANIFEST);
assertEquals(imageRegisteredFromManifest.getImageType(), ImageType.MACHINE);
@ -146,10 +146,10 @@ public class AMIClientLiveTest {
@Test(enabled = false)
public void testRegisterImageFromManifestOptions() {
String imageRegisteredWithOptionsId = client.registerImageFromManifestInRegion(null, "jcloudstest2",
DEFAULT_MANIFEST, withDescription("adrian"));
DEFAULT_MANIFEST, withDescription("adrian"));
imagesToDeregister.add(imageRegisteredWithOptionsId);
Image imageRegisteredFromManifestWithOptions = Iterables.getOnlyElement(client.describeImagesInRegion(null,
imageIds(imageRegisteredWithOptionsId)));
imageIds(imageRegisteredWithOptionsId)));
assertEquals(imageRegisteredFromManifestWithOptions.getName(), "jcloudstest2");
assertEquals(imageRegisteredFromManifestWithOptions.getImageLocation(), DEFAULT_MANIFEST);
assertEquals(imageRegisteredFromManifestWithOptions.getImageType(), ImageType.MACHINE);
@ -164,7 +164,7 @@ public class AMIClientLiveTest {
String imageRegisteredId = client.registerUnixImageBackedByEbsInRegion(null, "jcloudstest1", DEFAULT_MANIFEST);
imagesToDeregister.add(imageRegisteredId);
Image imageRegistered = Iterables
.getOnlyElement(client.describeImagesInRegion(null, imageIds(imageRegisteredId)));
.getOnlyElement(client.describeImagesInRegion(null, imageIds(imageRegisteredId)));
assertEquals(imageRegistered.getName(), "jcloudstest1");
assertEquals(imageRegistered.getImageType(), ImageType.MACHINE);
assertEquals(imageRegistered.getRootDeviceType(), RootDeviceType.EBS);
@ -175,18 +175,19 @@ public class AMIClientLiveTest {
// awaiting EBS functionality to be added to jclouds
public void testRegisterImageBackedByEBSOptions() {
String imageRegisteredWithOptionsId = client.registerUnixImageBackedByEbsInRegion(null, "jcloudstest2",
DEFAULT_SNAPSHOT, addNewBlockDevice("/dev/sda2", "myvirtual", 1).withDescription("adrian"));
DEFAULT_SNAPSHOT, addNewBlockDevice("/dev/sda2", "myvirtual", 1).withDescription("adrian"));
imagesToDeregister.add(imageRegisteredWithOptionsId);
Image imageRegisteredWithOptions = Iterables.getOnlyElement(client.describeImagesInRegion(null,
imageIds(imageRegisteredWithOptionsId)));
imageIds(imageRegisteredWithOptionsId)));
assertEquals(imageRegisteredWithOptions.getName(), "jcloudstest2");
assertEquals(imageRegisteredWithOptions.getImageType(), ImageType.MACHINE);
assertEquals(imageRegisteredWithOptions.getRootDeviceType(), RootDeviceType.EBS);
assertEquals(imageRegisteredWithOptions.getRootDeviceName(), "/dev/sda1");
assertEquals(imageRegisteredWithOptions.getDescription(), "adrian");
assertEquals(imageRegisteredWithOptions.getEbsBlockDevices().entrySet(), ImmutableMap.of("/dev/sda1",
new Image.EbsBlockDevice("/dev/sda1", 30, true), "/dev/sda2",
new Image.EbsBlockDevice("/dev/sda2", 1, true)).entrySet());
assertEquals(
imageRegisteredWithOptions.getEbsBlockDevices().entrySet(),
ImmutableMap.of("/dev/sda1", new Image.EbsBlockDevice("/dev/sda1", 30, true), "/dev/sda2",
new Image.EbsBlockDevice("/dev/sda2", 1, true)).entrySet());
}
@Test(enabled = false)
@ -216,6 +217,7 @@ public class AMIClientLiveTest {
// TODO client.resetLaunchPermissionsOnImageInRegion(null, imageId);
}
@Test(enabled = false)
public void testGetLaunchPermissionForImage() {
System.out.println(client.getLaunchPermissionForImageInRegion(null, imageId));
}

View File

@ -41,6 +41,7 @@ import org.jclouds.Constants;
import org.jclouds.aws.domain.Region;
import org.jclouds.aws.ec2.AWSEC2AsyncClient;
import org.jclouds.aws.ec2.AWSEC2Client;
import org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions;
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ComputeServiceContextFactory;
@ -49,10 +50,7 @@ import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.domain.Credentials;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.domain.KeyPair;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.services.InstanceClient;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rest.RestContext;
import org.jclouds.ssh.jsch.config.JschSshClientModule;
@ -84,7 +82,7 @@ public class AWSKeyPairClientLiveTest {
protected void setupCredentials() {
identity = checkNotNull(System.getProperty("test." + provider + ".identity"), "test." + provider + ".identity");
credential = checkNotNull(System.getProperty("test." + provider + ".credential"), "test." + provider
+ ".credential");
+ ".credential");
endpoint = System.getProperty("test." + provider + ".endpoint", null);
apiversion = System.getProperty("test." + provider + ".apiversion", null);
}
@ -106,8 +104,8 @@ public class AWSKeyPairClientLiveTest {
public void setupClient() {
setupCredentials();
Properties overrides = setupProperties();
computeContext = new ComputeServiceContextFactory().createContext(provider,
ImmutableSet.<Module> of(new Log4JLoggingModule(), new JschSshClientModule()), overrides);
computeContext = new ComputeServiceContextFactory().createContext(provider, ImmutableSet.<Module> of(
new Log4JLoggingModule(), new JschSshClientModule()), overrides);
context = computeContext.getProviderSpecificContext();
client = context.getApi().getKeyPairServices();
}
@ -116,19 +114,19 @@ public class AWSKeyPairClientLiveTest {
Map<String, String> keyPair = ComputeTestUtils.setupKeyPair();
InstanceClient instanceClient = EC2Client.class.cast(context.getApi()).getInstanceServices();
AWSInstanceClient instanceClient = AWSEC2Client.class.cast(context.getApi()).getInstanceServices();
String group = PREFIX + "unssh";
computeContext.getComputeService().destroyNodesMatching(inGroup(group));
TemplateOptions options = computeContext.getComputeService().templateOptions();
options.authorizePublicKey(keyPair.get("public"));
options.authorizePublicKey(keyPair.get("public")).as(AWSEC2TemplateOptions.class).spotPrice(0.3f);
ComputeServiceContext noSshContext = null;
try {
noSshContext = new ComputeServiceContextFactory().createContext(provider,
ImmutableSet.of(new Log4JLoggingModule()), setupProperties());
noSshContext = new ComputeServiceContextFactory().createContext(provider, ImmutableSet
.of(new Log4JLoggingModule()), setupProperties());
Set<? extends NodeMetadata> nodes = noSshContext.getComputeService().createNodesInGroup(group, 1, options);
@ -136,18 +134,19 @@ public class AWSKeyPairClientLiveTest {
assert first.getCredentials() != null : first;
assert first.getCredentials().identity != null : first;
AWSRunningInstance instance = AWSRunningInstance.class
.cast(getInstance(instanceClient, first.getProviderId()));
AWSRunningInstance instance = getInstance(instanceClient, first.getProviderId());
assert instance.getSpotInstanceRequestId() != null : instance;
assertEquals(instance.getKeyName(), "jclouds#" + group);
assertEquals(first.getCredentials().credential, null);
Map<? extends NodeMetadata, ExecResponse> responses = computeContext.getComputeService()
.runScriptOnNodesMatching(
runningInGroup(group),
exec("echo hello"),
overrideCredentialsWith(new Credentials(first.getCredentials().identity, keyPair.get("private")))
.wrapInInitScript(false).runAsRoot(false));
.runScriptOnNodesMatching(
runningInGroup(group),
exec("echo hello"),
overrideCredentialsWith(
new Credentials(first.getCredentials().identity, keyPair.get("private")))
.wrapInInitScript(false).runAsRoot(false));
ExecResponse hello = getOnlyElement(responses.values());
assertEquals(hello.getOutput().trim(), "hello");
@ -235,9 +234,8 @@ public class AWSKeyPairClientLiveTest {
assertEquals(listPair.getKeyFingerprint(), keyPair.getKeyFingerprint());
}
protected RunningInstance getInstance(InstanceClient instanceClient, String id) {
RunningInstance instance = getOnlyElement(getOnlyElement(instanceClient.describeInstancesInRegion(null, id)));
return instance;
protected AWSRunningInstance getInstance(AWSInstanceClient instanceClient, String id) {
return getOnlyElement(getOnlyElement(instanceClient.describeInstancesInRegion(null, id)));
}
@AfterTest

View File

@ -0,0 +1,190 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.services;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Date;
import org.jclouds.aws.ec2.domain.LaunchSpecification;
import org.jclouds.aws.ec2.options.DescribeSpotPriceHistoryOptions;
import org.jclouds.aws.ec2.options.RequestSpotInstancesOptions;
import org.jclouds.aws.ec2.xml.DescribeSpotPriceHistoryResponseHandler;
import org.jclouds.aws.ec2.xml.SpotInstanceHandler;
import org.jclouds.aws.ec2.xml.SpotInstancesHandler;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ReleasePayloadAndReturn;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.Test;
import com.google.inject.TypeLiteral;
/**
* Tests behavior of {@code SpotInstanceAsyncClient}
*
* @author Adrian Cole
*/
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "SpotInstanceAsyncClientTest")
public class SpotInstanceAsyncClientTest extends BaseAWSEC2AsyncClientTest<SpotInstanceAsyncClient> {
public void testRequestSpotInstance() throws SecurityException, NoSuchMethodException, IOException {
Method method = SpotInstanceAsyncClient.class.getMethod("requestSpotInstanceInRegion", String.class,
float.class, String.class, String.class);
HttpRequest request = processor.createRequest(method, null, 0.01f, "m1.small", "ami-voo");
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
assertPayloadEquals(
request,
"Version=2010-11-15&Action=RequestSpotInstances&LaunchSpecification.ImageId=m1.small&SpotPrice=0.01&LaunchSpecification.InstanceType=ami-voo",
"application/x-www-form-urlencoded", false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, SpotInstanceHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(request);
}
public void testRequestSpotInstancesOptions() throws SecurityException, NoSuchMethodException, IOException {
Method method = SpotInstanceAsyncClient.class.getMethod("requestSpotInstancesInRegion", String.class,
float.class, int.class, LaunchSpecification.class, RequestSpotInstancesOptions[].class);
HttpRequest request = processor.createRequest(method, "eu-west-1", 0.01, 3,
LaunchSpecification.builder().instanceType("m1.small").imageId("ami-voo").availabilityZone("eu-west-1a")
.kernelId("kernelId").groupId("group1").build(), new RequestSpotInstancesOptions().validFrom(from)
.validUntil(to).availabilityZoneGroup("availabilityZoneGroup").launchGroup("launchGroup"));
assertRequestLineEquals(request, "POST https://ec2.eu-west-1.amazonaws.com/ HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Host: ec2.eu-west-1.amazonaws.com\n");
assertPayloadEquals(
request,
"Version=2010-11-15&Action=RequestSpotInstances&InstanceCount=3&SpotPrice=0.01&ValidFrom=1970-05-23T21%3A21%3A18.910Z&ValidUntil=2009-02-13T23%3A31%3A31.011Z&AvailabilityZoneGroup=availabilityZoneGroup&LaunchGroup=launchGroup&LaunchSpecification.ImageId=ami-voo&LaunchSpecification.Placement.AvailabilityZone=eu-west-1a&LaunchSpecification.SecurityGroup.1=group1&LaunchSpecification.InstanceType=m1.small&LaunchSpecification.KernelId=kernelId",
"application/x-www-form-urlencoded", false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, SpotInstancesHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(request);
}
public void testCancelSpotInstanceRequests() throws SecurityException, NoSuchMethodException, IOException {
Method method = SpotInstanceAsyncClient.class.getMethod("cancelSpotInstanceRequestsInRegion", String.class,
String[].class);
HttpRequest request = processor.createRequest(method, null, "id");
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
assertPayloadEquals(request, "Version=2010-11-15&Action=CancelSpotInstanceRequests&SpotInstanceRequestId.1=id",
"application/x-www-form-urlencoded", false);
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnVoidOnNotFoundOr404.class);
checkFilters(request);
}
public void testDescribeSpotInstanceRequests() throws SecurityException, NoSuchMethodException, IOException {
Method method = SpotInstanceAsyncClient.class.getMethod("describeSpotInstanceRequestsInRegion", String.class,
String[].class);
HttpRequest request = processor.createRequest(method, (String) null);
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
assertPayloadEquals(request, "Version=2010-11-15&Action=DescribeSpotInstanceRequests",
"application/x-www-form-urlencoded", false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, SpotInstancesHandler.class);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(request);
}
public void testDescribeSpotInstanceRequestsArgs() throws SecurityException, NoSuchMethodException, IOException {
Method method = SpotInstanceAsyncClient.class.getMethod("describeSpotInstanceRequestsInRegion", String.class,
String[].class);
HttpRequest request = processor.createRequest(method, null, "1", "2");
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
assertPayloadEquals(
request,
"Version=2010-11-15&Action=DescribeSpotInstanceRequests&SpotInstanceRequestId.1=1&SpotInstanceRequestId.2=2",
"application/x-www-form-urlencoded", false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, SpotInstancesHandler.class);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(request);
}
public void testDescribeSpotPriceHistory() throws SecurityException, NoSuchMethodException, IOException {
Method method = SpotInstanceAsyncClient.class.getMethod("describeSpotPriceHistoryInRegion", String.class,
DescribeSpotPriceHistoryOptions[].class);
HttpRequest request = processor.createRequest(method, (String) null);
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
assertPayloadEquals(request, "Version=2010-11-15&Action=DescribeSpotPriceHistory",
"application/x-www-form-urlencoded", false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, DescribeSpotPriceHistoryResponseHandler.class);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(request);
}
Date from = new Date(12345678910l);
Date to = new Date(1234567891011l);
public void testDescribeSpotPriceHistoryArgs() throws SecurityException, NoSuchMethodException, IOException {
Method method = SpotInstanceAsyncClient.class.getMethod("describeSpotPriceHistoryInRegion", String.class,
DescribeSpotPriceHistoryOptions[].class);
HttpRequest request = processor.createRequest(method, null, DescribeSpotPriceHistoryOptions.Builder.from(from)
.to(to).productDescription("description").instanceType("m1.small"));
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
assertPayloadEquals(
request,
"Version=2010-11-15&Action=DescribeSpotPriceHistory&StartTime=1970-05-23T21%3A21%3A18.910Z&EndTime=2009-02-13T23%3A31%3A31.011Z&ProductDescription=description&InstanceType.1=m1.small",
"application/x-www-form-urlencoded", false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, DescribeSpotPriceHistoryResponseHandler.class);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(request);
}
@Override
protected TypeLiteral<RestAnnotationProcessor<SpotInstanceAsyncClient>> createTypeLiteral() {
return new TypeLiteral<RestAnnotationProcessor<SpotInstanceAsyncClient>>() {
};
}
}

View File

@ -0,0 +1,207 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.services;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.in;
import static com.google.common.collect.Iterables.getOnlyElement;
import static org.jclouds.aws.ec2.options.DescribeSpotPriceHistoryOptions.Builder.from;
import static org.jclouds.aws.ec2.options.RequestSpotInstancesOptions.Builder.launchGroup;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Date;
import java.util.Properties;
import java.util.Set;
import java.util.SortedSet;
import java.util.concurrent.TimeUnit;
import org.jclouds.Constants;
import org.jclouds.aws.domain.Region;
import org.jclouds.aws.ec2.AWSEC2Client;
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
import org.jclouds.aws.ec2.domain.LaunchSpecification;
import org.jclouds.aws.ec2.domain.Spot;
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
import org.jclouds.aws.ec2.predicates.SpotInstanceRequestActive;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ComputeServiceContextFactory;
import org.jclouds.ec2.domain.InstanceType;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.ssh.jsch.config.JschSshClientModule;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.inject.Module;
/**
* Tests behavior of {@code SpotInstanceClient}
*
* @author Adrian Cole
*/
@Test(groups = "live", sequential = true)
public class SpotInstanceClientLiveTest {
private static final int SPOT_DELAY_SECONDS = 300;
private AWSEC2Client client;
private ComputeServiceContext context;
private RetryablePredicate<SpotInstanceRequest> activeTester;
private Set<SpotInstanceRequest> requests;
protected String provider = "aws-ec2";
protected String identity;
protected String credential;
protected String endpoint;
protected String apiversion;
private AWSRunningInstance instance;
private long start;
@BeforeClass
protected void setupCredentials() {
identity = checkNotNull(System.getProperty("test." + provider + ".identity"), "test." + provider + ".identity");
credential = System.getProperty("test." + provider + ".credential");
endpoint = System.getProperty("test." + provider + ".endpoint");
apiversion = System.getProperty("test." + provider + ".apiversion");
}
protected Properties setupProperties() {
Properties overrides = new Properties();
overrides.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, "true");
overrides.setProperty(Constants.PROPERTY_RELAX_HOSTNAME, "true");
overrides.setProperty(provider + ".identity", identity);
if (credential != null)
overrides.setProperty(provider + ".credential", credential);
if (endpoint != null)
overrides.setProperty(provider + ".endpoint", endpoint);
if (apiversion != null)
overrides.setProperty(provider + ".apiversion", apiversion);
return overrides;
}
@BeforeGroups(groups = { "live" })
public void setupClient() throws FileNotFoundException, IOException {
setupCredentials();
Properties overrides = setupProperties();
context = new ComputeServiceContextFactory().createContext(provider,
ImmutableSet.<Module> of(new Log4JLoggingModule(), new JschSshClientModule()), overrides);
client = AWSEC2Client.class.cast(context.getProviderSpecificContext().getApi());
activeTester = new RetryablePredicate<SpotInstanceRequest>(new SpotInstanceRequestActive(client),
SPOT_DELAY_SECONDS, 1, 1, TimeUnit.SECONDS);
}
@Test
void testDescribeSpotRequestsInRegion() {
for (String region : Region.DEFAULT_REGIONS) {
SortedSet<SpotInstanceRequest> allResults = ImmutableSortedSet.copyOf(client.getSpotInstanceServices()
.describeSpotInstanceRequestsInRegion(region));
assertNotNull(allResults);
if (allResults.size() >= 1) {
SpotInstanceRequest request = allResults.last();
SortedSet<SpotInstanceRequest> result = ImmutableSortedSet.copyOf(client.getSpotInstanceServices()
.describeSpotInstanceRequestsInRegion(region, request.getId()));
assertNotNull(result);
SpotInstanceRequest compare = result.last();
assertEquals(compare, request);
}
}
}
@Test
void testDescribeSpotPriceHistoryInRegion() {
for (final String region : Region.DEFAULT_REGIONS) {
Set<Spot> spots = client.getSpotInstanceServices().describeSpotPriceHistoryInRegion(region, from(new Date()));
assertNotNull(spots);
assert spots.size() > 0;
for (Spot spot : spots) {
assert spot.getSpotPrice() > 0 : spots;
assertEquals(spot.getRegion(), region);
assert in(ImmutableSet.of("Linux/UNIX", "SUSE Linux", "Windows")).apply(spot.getProductDescription()) : spot;
assert in(
ImmutableSet.of("c1.medium", "c1.xlarge", "m1.large", "m1.small", "m1.xlarge", "m2.2xlarge",
"m2.4xlarge", "m2.xlarge", "t1.micro")).apply(spot.getInstanceType()) : spot;
}
}
}
@Test(enabled = true)
void testCreateSpotInstance() {
String launchGroup = PREFIX + "1";
for (SpotInstanceRequest request : client.getSpotInstanceServices().describeSpotInstanceRequestsInRegion(
"us-west-1"))
if (launchGroup.equals(request.getLaunchGroup()))
client.getSpotInstanceServices().cancelSpotInstanceRequestsInRegion("us-west-1", request.getId());
start = System.currentTimeMillis();
requests = client.getSpotInstanceServices().requestSpotInstancesInRegion(
"us-west-1",
0.03f,
1,
LaunchSpecification.builder().imageId("ami-595a0a1c").instanceType(InstanceType.T1_MICRO).build(),
launchGroup(launchGroup).availabilityZoneGroup(launchGroup).validFrom(new Date())
.validUntil(new Date(System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(SPOT_DELAY_SECONDS))));
assertNotNull(requests);
for (SpotInstanceRequest request : requests)
verifySpotInstance(request);
}
private void verifySpotInstance(SpotInstanceRequest request) {
SpotInstanceRequest spot = refresh(request);
assertNotNull(spot);
assertEquals(spot, request);
assert activeTester.apply(request) : refresh(request);
System.out.println(System.currentTimeMillis() - start);
spot = refresh(request);
assert spot.getInstanceId() != null : spot;
instance = getOnlyElement(getOnlyElement(client.getInstanceServices().describeInstancesInRegion("us-west-1",
spot.getInstanceId())));
assertEquals(instance.getSpotInstanceRequestId(), spot.getId());
}
public SpotInstanceRequest refresh(SpotInstanceRequest request) {
return getOnlyElement(client.getSpotInstanceServices().describeSpotInstanceRequestsInRegion("us-west-1",
request.getId()));
}
public static final String PREFIX = System.getProperty("user.name") + "ec2";
@AfterTest
public void shutdown() {
if (requests != null) {
for (SpotInstanceRequest request : requests)
client.getSpotInstanceServices().cancelSpotInstanceRequestsInRegion(request.getRegion(), request.getId());
// assert deletedTester.apply(request) : request;
}
if (instance != null) {
client.getInstanceServices().terminateInstancesInRegion("us-west-1", instance.getId());
}
context.close();
}
}

View File

@ -53,7 +53,7 @@ import com.google.inject.Guice;
*/
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "RunInstancesResponseHandlerTest")
public class RunInstancesResponseHandlerTest extends BaseEC2HandlerTest {
public class AWSRunInstancesResponseHandlerTest extends BaseEC2HandlerTest {
private DateService dateService;

View File

@ -0,0 +1,69 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com("
*
* ====================================================================
* Licensed 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.aws.ec2.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.util.Set;
import org.jclouds.aws.ec2.domain.Spot;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.location.Region;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.inject.AbstractModule;
/**
* Tests behavior of {@code DescribeSpotPriceHistoryResponseHandler}
*
* @author Adrian Cole
*/
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "DescribeSpotPriceHistoryResponseHandlerTest")
public class DescribeSpotPriceHistoryResponseHandlerTest extends BaseHandlerTest {
public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/describe_spot_price_history.xml");
Set<Spot> expected = ImmutableSet.of(
Spot.builder().region("us-west-1").instanceType("t1.micro").productDescription("SUSE Linux").spotPrice(0.013f)
.timestamp(new SimpleDateFormatDateService().iso8601DateParse("2011-03-07T12:17:19.000Z")).build(),
Spot.builder().region("us-west-1").instanceType("m1.large").productDescription("Linux/UNIX").spotPrice(0.119f)
.timestamp(new SimpleDateFormatDateService().iso8601DateParse("2011-03-07T16:29:16.000Z")).build(),
Spot.builder().region("us-west-1").instanceType("t1.micro").productDescription("Windows").spotPrice(0.013f)
.timestamp(new SimpleDateFormatDateService().iso8601DateParse("2011-03-07T17:56:54.000Z")).build()
);
Set<Spot> result = factory.create(injector.createChildInjector(new AbstractModule(){
@Override
protected void configure() {
bindConstant().annotatedWith(Region.class).to("us-west-1");
}
}).getInstance(DescribeSpotPriceHistoryResponseHandler.class)).parse(is);
assertEquals(result, expected);
}
}

View File

@ -0,0 +1,102 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. .info@cloudconscious.com("
*
* ====================================================================
* Licensed 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.aws.ec2.xml;
import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import org.jclouds.aws.ec2.domain.LaunchSpecification;
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
import org.jclouds.date.DateService;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.ec2.xml.BaseEC2HandlerTest;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.config.SaxParserModule;
import org.jclouds.location.Region;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
/**
* Tests behavior of {@code SpotInstanceHandler}
*
* @author Adrian Cole
*/
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "SpotInstanceHandlerTest")
public class SpotInstanceHandlerTest extends BaseEC2HandlerTest {
private DateService dateService;
@BeforeTest
@Override
protected void setUpInjector() {
injector = Guice.createInjector(new SaxParserModule(), new AbstractModule() {
@Override
protected void configure() {
bind(String.class).annotatedWith(Region.class).toInstance("us-east-1");
}
});
factory = injector.getInstance(ParseSax.Factory.class);
dateService = injector.getInstance(DateService.class);
assert dateService != null;
}
public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/request_spot_instances-ebs.xml");
SpotInstanceRequest expected = SpotInstanceRequest
.builder()
.region("us-east-1")
.id("sir-228e6406")
.spotPrice(0.001f)
.type(SpotInstanceRequest.Type.ONE_TIME)
.state(SpotInstanceRequest.State.OPEN)
.launchSpecification(
LaunchSpecification.builder().imageId("ami-595a0a1c").groupId("default").instanceType("m1.large")
.mapNewVolumeToDevice("/dev/sda1", 1, true)
.mapEBSSnapshotToDevice("/dev/sda2", "snap-1ea27576", 1, true)
.mapEphemeralDeviceToDevice("/dev/sda3", "vre1").monitoringEnabled(false).build())
.createTime(new SimpleDateFormatDateService().iso8601DateParse("2011-03-08T03:30:36.000Z"))
.productDescription("Linux/UNIX").build();
SpotInstanceHandler handler = injector.getInstance(SpotInstanceHandler.class);
addDefaultRegionToHandler(handler);
SpotInstanceRequest result = factory.create(handler).parse(is);
assertEquals(result, expected);
}
private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) {
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
expect(request.getArgs()).andReturn(ImmutableList.<Object> of()).atLeastOnce();
replay(request);
handler.setContext(request);
}
}

View File

@ -0,0 +1,95 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. .info@cloudconscious.com("
*
* ====================================================================
* Licensed 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.aws.ec2.xml;
import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.util.Set;
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
import org.jclouds.date.DateService;
import org.jclouds.ec2.xml.BaseEC2HandlerTest;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.config.SaxParserModule;
import org.jclouds.location.Region;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
/**
* Tests behavior of {@code SpotInstancesHandler}
*
* @author Adrian Cole
*/
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "SpotInstancesHandlerTest")
public class SpotInstancesHandlerTest extends BaseEC2HandlerTest {
private DateService dateService;
@BeforeTest
@Override
protected void setUpInjector() {
injector = Guice.createInjector(new SaxParserModule(), new AbstractModule() {
@Override
protected void configure() {
bind(String.class).annotatedWith(Region.class).toInstance("us-east-1");
}
});
factory = injector.getInstance(ParseSax.Factory.class);
dateService = injector.getInstance(DateService.class);
assert dateService != null;
}
public void testDescribe() {
InputStream is = getClass().getResourceAsStream("/describe_spot_instance_requests.xml");
SpotInstancesHandler handler = injector
.getInstance(SpotInstancesHandler.class);
addDefaultRegionToHandler(handler);
Set<SpotInstanceRequest> result = factory.create(handler).parse(is);
assertEquals(result.size(), 18);
}
public void testRequest() {
InputStream is = getClass().getResourceAsStream("/request_spot_instances.xml");
SpotInstancesHandler handler = injector
.getInstance(SpotInstancesHandler.class);
addDefaultRegionToHandler(handler);
Set<SpotInstanceRequest> result = factory.create(handler).parse(is);
assertEquals(result.size(), 3);
}
private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) {
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
expect(request.getArgs()).andReturn(ImmutableList.<Object> of()).atLeastOnce();
replay(request);
handler.setContext(request);
}
}

View File

@ -0,0 +1,413 @@
<DescribeSpotInstanceRequestsResponse xmlns="http://ec2.amazonaws.com/doc/2010-11-15/">
<requestId>7c4dd2bd-106d-4cd3-987c-35ee819180a6</requestId>
<spotInstanceRequestSet>
<item>
<spotInstanceRequestId>sir-067a4805</spotInstanceRequestId>
<spotPrice>0.040000</spotPrice>
<type>one-time</type>
<state>cancelled</state>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<groupSet>
<item>
<groupId>default</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping/>
<monitoring>
<enabled>false</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-07T20:13:07.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
<item>
<spotInstanceRequestId>sir-aa67d410</spotInstanceRequestId>
<spotPrice>0.040000</spotPrice>
<type>one-time</type>
<state>cancelled</state>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<groupSet>
<item>
<groupId>default</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping/>
<monitoring>
<enabled>false</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-07T20:13:57.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
<item>
<spotInstanceRequestId>sir-32e32810</spotInstanceRequestId>
<spotPrice>0.010000</spotPrice>
<type>one-time</type>
<state>cancelled</state>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<groupSet>
<item>
<groupId>default</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping/>
<monitoring>
<enabled>false</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-07T20:15:52.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
<item>
<spotInstanceRequestId>sir-46a36210</spotInstanceRequestId>
<spotPrice>0.010000</spotPrice>
<type>one-time</type>
<state>cancelled</state>
<validUntil>2011-03-07T20:20:00.000Z</validUntil>
<launchGroup>foo</launchGroup>
<availabilityZoneGroup>azfoo</availabilityZoneGroup>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<keyName>default</keyName>
<groupSet>
<item>
<groupId>quick-start-1</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping/>
<monitoring>
<enabled>true</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-07T20:18:25.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
<item>
<spotInstanceRequestId>sir-91780010</spotInstanceRequestId>
<spotPrice>0.010000</spotPrice>
<type>one-time</type>
<state>cancelled</state>
<validUntil>2011-03-07T20:20:00.000Z</validUntil>
<launchGroup>foo</launchGroup>
<availabilityZoneGroup>azfoo</availabilityZoneGroup>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<keyName>default</keyName>
<groupSet>
<item>
<groupId>quick-start-1</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping/>
<monitoring>
<enabled>true</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-07T20:18:25.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
<item>
<spotInstanceRequestId>sir-6f1fa605</spotInstanceRequestId>
<spotPrice>0.001000</spotPrice>
<type>one-time</type>
<state>cancelled</state>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<groupSet>
<item>
<groupId>default</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping/>
<monitoring>
<enabled>false</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-07T20:19:27.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
<item>
<spotInstanceRequestId>sir-a33eee10</spotInstanceRequestId>
<spotPrice>0.001000</spotPrice>
<type>one-time</type>
<state>cancelled</state>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<groupSet>
<item>
<groupId>default</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping/>
<monitoring>
<enabled>false</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-07T20:21:16.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
<item>
<spotInstanceRequestId>sir-aa690410</spotInstanceRequestId>
<spotPrice>0.001000</spotPrice>
<type>one-time</type>
<state>cancelled</state>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<groupSet>
<item>
<groupId>default</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping/>
<monitoring>
<enabled>false</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-07T20:21:52.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
<item>
<spotInstanceRequestId>sir-99ba4e06</spotInstanceRequestId>
<spotPrice>0.010000</spotPrice>
<type>one-time</type>
<state>cancelled</state>
<validUntil>2011-03-07T20:26:00.000Z</validUntil>
<launchGroup>doo</launchGroup>
<availabilityZoneGroup>dooo</availabilityZoneGroup>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<keyName>default</keyName>
<groupSet>
<item>
<groupId>quick-start-1</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping/>
<monitoring>
<enabled>true</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-07T20:24:30.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
<item>
<spotInstanceRequestId>sir-a617c406</spotInstanceRequestId>
<spotPrice>0.010000</spotPrice>
<type>one-time</type>
<state>cancelled</state>
<validUntil>2011-03-07T20:26:00.000Z</validUntil>
<launchGroup>doo</launchGroup>
<availabilityZoneGroup>dooo</availabilityZoneGroup>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<keyName>default</keyName>
<groupSet>
<item>
<groupId>quick-start-1</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping/>
<monitoring>
<enabled>true</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-07T20:24:30.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
<item>
<spotInstanceRequestId>sir-2147a405</spotInstanceRequestId>
<spotPrice>0.001000</spotPrice>
<type>one-time</type>
<state>cancelled</state>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<groupSet>
<item>
<groupId>default</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping/>
<monitoring>
<enabled>false</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-07T20:25:19.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
<item>
<spotInstanceRequestId>sir-c441c805</spotInstanceRequestId>
<spotPrice>0.001000</spotPrice>
<type>one-time</type>
<state>cancelled</state>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<groupSet>
<item>
<groupId>default</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping/>
<monitoring>
<enabled>false</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-07T20:29:09.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
<item>
<spotInstanceRequestId>sir-4658fe10</spotInstanceRequestId>
<spotPrice>0.010000</spotPrice>
<type>one-time</type>
<state>cancelled</state>
<validUntil>2011-03-07T21:10:00.000Z</validUntil>
<launchGroup>check3</launchGroup>
<availabilityZoneGroup>check3</availabilityZoneGroup>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<keyName>default</keyName>
<groupSet>
<item>
<groupId>quick-start-1</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping/>
<monitoring>
<enabled>false</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-07T20:31:34.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
<item>
<spotInstanceRequestId>sir-49a3ce10</spotInstanceRequestId>
<spotPrice>0.010000</spotPrice>
<type>one-time</type>
<state>cancelled</state>
<validUntil>2011-03-07T21:10:00.000Z</validUntil>
<launchGroup>check3</launchGroup>
<availabilityZoneGroup>check3</availabilityZoneGroup>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<keyName>default</keyName>
<groupSet>
<item>
<groupId>quick-start-1</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping/>
<monitoring>
<enabled>false</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-07T20:31:34.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
<item>
<spotInstanceRequestId>sir-91b30610</spotInstanceRequestId>
<spotPrice>0.010000</spotPrice>
<type>one-time</type>
<state>cancelled</state>
<validUntil>2011-03-07T21:10:00.000Z</validUntil>
<launchGroup>check3</launchGroup>
<availabilityZoneGroup>check3</availabilityZoneGroup>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<keyName>default</keyName>
<groupSet>
<item>
<groupId>quick-start-1</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping/>
<monitoring>
<enabled>false</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-07T20:31:34.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
<item>
<spotInstanceRequestId>sir-d8561606</spotInstanceRequestId>
<spotPrice>0.001000</spotPrice>
<type>one-time</type>
<state>cancelled</state>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<groupSet>
<item>
<groupId>default</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping/>
<monitoring>
<enabled>false</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-07T20:34:10.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
<item>
<spotInstanceRequestId>sir-4cdaa406</spotInstanceRequestId>
<spotPrice>0.001000</spotPrice>
<type>persistent</type>
<state>cancelled</state>
<validUntil>2011-03-07T22:25:00.000Z</validUntil>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<keyName>default</keyName>
<groupSet>
<item>
<groupId>quick-start-1</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping/>
<monitoring>
<enabled>false</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-07T22:23:19.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
<item>
<spotInstanceRequestId>sir-e19f2206</spotInstanceRequestId>
<spotPrice>0.001000</spotPrice>
<type>one-time</type>
<state>open</state>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<groupSet>
<item>
<groupId>default</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping/>
<monitoring>
<enabled>false</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-07T22:32:50.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
</spotInstanceRequestSet>
</DescribeSpotInstanceRequestsResponse>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<DescribeSpotPriceHistoryResponse xmlns="http://ec2.amazonaws.com/doc/2010-11-15/">
<requestId>99777a75-2a2b-4296-a305-650c442d2d63</requestId>
<spotPriceHistorySet>
<item>
<instanceType>t1.micro</instanceType>
<productDescription>SUSE Linux</productDescription>
<spotPrice>0.013000</spotPrice>
<timestamp>2011-03-07T12:17:19.000Z</timestamp>
</item>
<item>
<instanceType>m1.large</instanceType>
<productDescription>Linux/UNIX</productDescription>
<spotPrice>0.119000</spotPrice>
<timestamp>2011-03-07T16:29:16.000Z</timestamp>
</item>
<item>
<instanceType>t1.micro</instanceType>
<productDescription>Windows</productDescription>
<spotPrice>0.013000</spotPrice>
<timestamp>2011-03-07T17:56:54.000Z</timestamp>
</item>
</spotPriceHistorySet>
</DescribeSpotPriceHistoryResponse>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<RequestSpotInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2010-11-15/">
<requestId>02401e8e-a4f5-4285-8ea8-6d742fbaadd8</requestId>
<spotInstanceRequestSet>
<item>
<spotInstanceRequestId>sir-228e6406</spotInstanceRequestId>
<spotPrice>0.001000</spotPrice>
<type>one-time</type>
<state>open</state>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<groupSet>
<item>
<groupId>default</groupId>
</item>
</groupSet>
<instanceType>m1.large</instanceType>
<blockDeviceMapping>
<item>
<deviceName>/dev/sda1</deviceName>
<ebs>
<volumeSize>1</volumeSize>
<deleteOnTermination>true</deleteOnTermination>
</ebs>
</item>
<item>
<deviceName>/dev/sda3</deviceName>
<virtualName>vre1</virtualName>
</item>
<item>
<deviceName>/dev/sda2</deviceName>
<ebs>
<snapshotId>snap-1ea27576</snapshotId>
<volumeSize>1</volumeSize>
<deleteOnTermination>true</deleteOnTermination>
</ebs>
</item>
</blockDeviceMapping>
<monitoring>
<enabled>false</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-08T03:30:36.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
</spotInstanceRequestSet>
</RequestSpotInstancesResponse>

View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<RequestSpotInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2010-11-15/">
<requestId>2ffc645f-6835-4d23-bd18-f6f53c253067</requestId>
<spotInstanceRequestSet>
<item>
<spotInstanceRequestId>sir-7c74f805</spotInstanceRequestId>
<spotPrice>0.001000</spotPrice>
<type>one-time</type>
<state>open</state>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<groupSet>
<item>
<groupId>default</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping>
<item>
<deviceName>/dev/sda1</deviceName>
<ebs>
<volumeSize>120</volumeSize>
<deleteOnTermination>true</deleteOnTermination>
</ebs>
</item>
</blockDeviceMapping>
<monitoring>
<enabled>false</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-08T02:36:32.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
<item>
<spotInstanceRequestId>sir-78ca7605</spotInstanceRequestId>
<spotPrice>0.001000</spotPrice>
<type>one-time</type>
<state>open</state>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<groupSet>
<item>
<groupId>default</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping>
<item>
<deviceName>/dev/sda1</deviceName>
<ebs>
<volumeSize>120</volumeSize>
<deleteOnTermination>true</deleteOnTermination>
</ebs>
</item>
</blockDeviceMapping>
<monitoring>
<enabled>false</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-08T02:36:32.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
<item>
<spotInstanceRequestId>sir-7e0f6005</spotInstanceRequestId>
<spotPrice>0.001000</spotPrice>
<type>one-time</type>
<state>open</state>
<launchSpecification>
<imageId>ami-595a0a1c</imageId>
<groupSet>
<item>
<groupId>default</groupId>
</item>
</groupSet>
<instanceType>t1.micro</instanceType>
<blockDeviceMapping>
<item>
<deviceName>/dev/sda1</deviceName>
<ebs>
<volumeSize>120</volumeSize>
<deleteOnTermination>true</deleteOnTermination>
</ebs>
</item>
</blockDeviceMapping>
<monitoring>
<enabled>false</enabled>
</monitoring>
</launchSpecification>
<createTime>2011-03-08T02:36:32.000Z</createTime>
<productDescription>Linux/UNIX</productDescription>
</item>
</spotInstanceRequestSet>
</RequestSpotInstancesResponse>

View File

@ -21,8 +21,6 @@ package org.jclouds.cloudstack.predicates;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.concurrent.ExecutionException;
import javax.annotation.Resource;
import javax.inject.Singleton;
@ -31,7 +29,6 @@ import org.jclouds.cloudstack.domain.AsyncJob;
import org.jclouds.logging.Logger;
import com.google.common.base.Predicate;
import com.google.common.base.Throwables;
import com.google.inject.Inject;
/**
@ -60,10 +57,8 @@ public class JobComplete implements Predicate<Long> {
return false;
logger.trace("%s: looking for job status %s: currently: %s", job.getId(), 1, job.getStatus());
if (job.getError() != null)
Throwables.propagate(new ExecutionException(String.format("job %s failed with exception %s", job.getId(), job
.getError().toString())) {
private static final long serialVersionUID = 4371112085613620239L;
});
throw new IllegalStateException(String.format("job %s failed with exception %s", job.getId(), job.getError()
.toString()));
return job.getStatus() > 0;
}