diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/binders/IfNotNullBindAvailabilityZoneToFormParam.java b/apis/ec2/src/main/java/org/jclouds/ec2/binders/IfNotNullBindAvailabilityZoneToFormParam.java index 1a2084fc4f..eeb4f03a89 100644 --- a/apis/ec2/src/main/java/org/jclouds/ec2/binders/IfNotNullBindAvailabilityZoneToFormParam.java +++ b/apis/ec2/src/main/java/org/jclouds/ec2/binders/IfNotNullBindAvailabilityZoneToFormParam.java @@ -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 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; } diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java b/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java index 431aab0663..c31c674e48 100644 --- a/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java +++ b/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java @@ -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 destroyNodesMatching(Predicate filter) { Set deadOnes = super.destroyNodesMatching(filter); - Builder regionGroups = ImmutableMap. builder(); + Builder regionGroups = ImmutableMultimap. builder(); for (NodeMetadata nodeMetadata : deadOnes) { if (nodeMetadata.getGroup() != null) regionGroups.put(AWSUtils.parseHandle(nodeMetadata.getId())[0], nodeMetadata.getGroup()); } - for (Entry regionGroup : regionGroups.build().entrySet()) { + for (Entry regionGroup : regionGroups.build().entries()) { cleanUpIncidentalResources(regionGroup); } return deadOnes; diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/compute/options/EC2TemplateOptions.java b/apis/ec2/src/main/java/org/jclouds/ec2/compute/options/EC2TemplateOptions.java index d469ad3605..1f1db3f8b8 100644 --- a/apis/ec2/src/main/java/org/jclouds/ec2/compute/options/EC2TemplateOptions.java +++ b/apis/ec2/src/main/java/org/jclouds/ec2/compute/options/EC2TemplateOptions.java @@ -89,7 +89,7 @@ public class EC2TemplateOptions extends TemplateOptions implements Cloneable { private String keyPair = null; private boolean noKeyPair; private byte[] userData; - private Set blockDeviceMappings = ImmutableSet.of(); + private ImmutableSet.Builder blockDeviceMappings = ImmutableSet. 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 mappings = ImmutableSet - . 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 mappings = ImmutableSet - . 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 mappings = ImmutableSet - . 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 mappings = ImmutableSet - . 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 blockDeviceMappings) { - this.blockDeviceMappings = ImmutableSet.copyOf(checkNotNull(blockDeviceMappings, "blockDeviceMappings")); + public EC2TemplateOptions blockDeviceMappings(Iterable 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 getBlockDeviceMappings() { - return blockDeviceMappings; + return blockDeviceMappings.build(); } @Override diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/domain/BlockDeviceMapping.java b/apis/ec2/src/main/java/org/jclouds/ec2/domain/BlockDeviceMapping.java index 0e6c3563f8..05d9e445b8 100644 --- a/apis/ec2/src/main/java/org/jclouds/ec2/domain/BlockDeviceMapping.java +++ b/apis/ec2/src/main/java/org/jclouds/ec2/domain/BlockDeviceMapping.java @@ -30,7 +30,64 @@ import org.jclouds.util.Preconditions2; * * @author Lili Nadar */ -public class BlockDeviceMapping { +public class BlockDeviceMapping implements Comparable{ + 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); + } } \ No newline at end of file diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/options/RunInstancesOptions.java b/apis/ec2/src/main/java/org/jclouds/ec2/options/RunInstancesOptions.java index 30c166afdc..f3d0481811 100644 --- a/apis/ec2/src/main/java/org/jclouds/ec2/options/RunInstancesOptions.java +++ b/apis/ec2/src/main/java/org/jclouds/ec2/options/RunInstancesOptions.java @@ -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 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; diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/options/internal/BaseEC2RequestOptions.java b/apis/ec2/src/main/java/org/jclouds/ec2/options/internal/BaseEC2RequestOptions.java index dd79c47635..037371cbe0 100644 --- a/apis/ec2/src/main/java/org/jclouds/ec2/options/internal/BaseEC2RequestOptions.java +++ b/apis/ec2/src/main/java/org/jclouds/ec2/options/internal/BaseEC2RequestOptions.java @@ -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 getFormValuesWithKeysPrefixedBy(final String prefix) { - Set values = Sets.newLinkedHashSet(); + Builder values = ImmutableSet. builder(); for (String key : Iterables.filter(formParameters.keySet(), new Predicate() { 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(); } } diff --git a/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java b/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java index cab0f53cd0..cca248b6a6 100644 --- a/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java +++ b/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java @@ -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(); diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2AsyncClient.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2AsyncClient.java index dc856615b3..634c855e86 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2AsyncClient.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2AsyncClient.java @@ -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(); } diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2Client.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2Client.java index 9a6f9087b6..91a5eaadac 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2Client.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2Client.java @@ -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(); } diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/binders/BindLaunchSpecificationToFormParams.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/binders/BindLaunchSpecificationToFormParams.java new file mode 100644 index 0000000000..db323eb46e --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/binders/BindLaunchSpecificationToFormParams.java @@ -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> { + + @Override + public 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 apply(LaunchSpecification launchSpec) { + Builder builder = ImmutableMap. 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 entry : options.buildFormParameters().entries()) { + builder.put("LaunchSpecification." + entry.getKey(), entry.getValue()); + } + return builder.build(); + } +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/binders/BindSpotInstanceRequestIdsToIndexedFormParams.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/binders/BindSpotInstanceRequestIdsToIndexedFormParams.java new file mode 100644 index 0000000000..479cccee0a --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/binders/BindSpotInstanceRequestIdsToIndexedFormParams.java @@ -0,0 +1,40 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 bindToRequest(R request, Object input) { + return AWSUtils.indexStringArrayToFormValuesWithPrefix(request, "SpotInstanceRequestId", input); + } + +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2TemplateOptions.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2TemplateOptions.java index a6f221d181..2dbb0e83a2 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2TemplateOptions.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2TemplateOptions.java @@ -294,7 +294,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab * {@inheritDoc} */ @Override - public AWSEC2TemplateOptions blockDeviceMappings(Set blockDeviceMappings) { + public AWSEC2TemplateOptions blockDeviceMappings(Iterable blockDeviceMappings) { return AWSEC2TemplateOptions.class.cast(super.blockDeviceMappings(blockDeviceMappings)); } diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/config/AWSEC2RestClientModule.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/config/AWSEC2RestClientModule.java index 719b3eb411..2fe4323885 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/config/AWSEC2RestClientModule.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/config/AWSEC2RestClientModule.java @@ -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 + * + * ==================================================================== + * 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 + * @author Adrian Cole + */ +public class LaunchSpecification { + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + protected ImmutableSet.Builder groupIds = ImmutableSet. 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 blockDeviceMappings = ImmutableSet + . builder(); + protected byte[] userData; + + public void clear() { + groupIds = ImmutableSet. builder(); + imageId = null; + instanceType = null; + kernelId = null; + keyName = null; + availabilityZone = null; + ramdiskId = null; + monitoringEnabled = false; + blockDeviceMappings = ImmutableSet. builder(); + userData = null; + } + + public Builder groupIds(Iterable 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 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 groupIds; + protected final Set blockDeviceMappings; + protected final Boolean monitoringEnabled; + protected final byte[] userData; + + public LaunchSpecification(String instanceType, String imageId, String kernelId, String ramdiskId, + String availabilityZone, String keyName, Iterable groupIds, + Iterable 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 getBlockDeviceMappings() { + return blockDeviceMappings; + } + + /** + * Names of the security groups. + */ + public Set 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) + "]"; + } + +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/Spot.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/Spot.java new file mode 100644 index 0000000000..a350c3f940 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/Spot.java @@ -0,0 +1,173 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 + * @author Adrian Cole + */ +public class Spot implements Comparable { + 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 + "]"; + } + +} \ No newline at end of file diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/SpotInstanceRequest.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/SpotInstanceRequest.java new file mode 100644 index 0000000000..adb52ad73c --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/SpotInstanceRequest.java @@ -0,0 +1,406 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 { + 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, 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); + } + +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/DescribeSpotPriceHistoryOptions.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/DescribeSpotPriceHistoryOptions.java new file mode 100644 index 0000000000..5f4176dd87 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/DescribeSpotPriceHistoryOptions.java @@ -0,0 +1,119 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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.

+ * Usage

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): + *

+ * + * import static org.jclouds.aws.ec2.options.DescribeSpotPriceHistoryOptions.Builder.* + *

+ * AWSEC2Client client = // get connection + * history = client.getSpotInstanceServices().describeSpotPriceHistoryInRegion(from(yesterday).instanceType("m1.small")); + * + * + * @author Adrian Cole + * @see + */ +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); + } + + } +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/RequestSpotInstancesOptions.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/RequestSpotInstancesOptions.java new file mode 100644 index 0000000000..e8e30eb265 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/RequestSpotInstancesOptions.java @@ -0,0 +1,142 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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.

+ * Usage

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): + *

+ * + * import static org.jclouds.aws.ec2.options.RequestSpotInstancesOptions.Builder.* + *

+ * AWSEC2Client client = // get connection + * history = client.getSpotInstanceServices().requestSpotInstancesInRegion("us-east-1",validFrom(yesterday).type("m1.small")); + * + * + * @author Adrian Cole + * @see + */ +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); + } + + } +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/predicates/SpotInstanceRequestActive.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/predicates/SpotInstanceRequestActive.java new file mode 100644 index 0000000000..d1b2b762c1 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/predicates/SpotInstanceRequestActive.java @@ -0,0 +1,83 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 java.util.concurrent.ExecutionException; + +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.base.Throwables; +import com.google.common.collect.Iterables; +import com.google.inject.Inject; + +/** + * + * + * @author Adrian Cole + */ +@Singleton +public class SpotInstanceRequestActive implements Predicate { + + 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) + Throwables.propagate(new ExecutionException(String.format("spot request %s cancelled", spot.getId())) { + private static final long serialVersionUID = 1L; + }); + if (spot.getFaultCode() != null) + Throwables.propagate(new ExecutionException(String.format("spot request %s fault code(%s) message(%s)", + spot.getId(), spot.getFaultCode(), spot.getFaultMessage())) { + private static final long serialVersionUID = 1L; + }); + 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())); + } +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/SpotInstanceAsyncClient.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/SpotInstanceAsyncClient.java new file mode 100644 index 0000000000..3d918adc12 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/SpotInstanceAsyncClient.java @@ -0,0 +1,128 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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. + *

+ * + * @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> 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 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> 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> describeSpotPriceHistoryInRegion( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + DescribeSpotPriceHistoryOptions... options); + + /** + * @see SpotInstanceClient#cancelSpotInstanceRequestsInRegion + */ + @POST + @Path("/") + @FormParams(keys = ACTION, values = "CancelSpotInstanceRequests") + @ExceptionParser(ReturnVoidOnNotFoundOr404.class) + ListenableFuture cancelSpotInstanceRequestsInRegion( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + @BinderParam(BindSpotInstanceRequestIdsToIndexedFormParams.class) String... requestIds); + +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/SpotInstanceClient.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/SpotInstanceClient.java new file mode 100644 index 0000000000..2771d4153b --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/SpotInstanceClient.java @@ -0,0 +1,159 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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. + *

+ * + * @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 + * @return TODO + */ + Set 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 + * @return set of spot instance requests + */ + Set 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 + * @return TODO + */ + @Timeout(duration = 2, timeUnit = TimeUnit.MINUTES) + Set 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 + * @return TODO + */ + String cancelSpotInstanceRequestsInRegion(@Nullable String region, String... requestIds); + +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/DescribeSpotPriceHistoryResponseHandler.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/DescribeSpotPriceHistoryResponseHandler.java new file mode 100644 index 0000000000..210ca4c711 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/DescribeSpotPriceHistoryResponseHandler.java @@ -0,0 +1,79 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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> { + + private Builder spots = ImmutableSet.builder(); + private final SpotHandler spotHandler; + + @Inject + public DescribeSpotPriceHistoryResponseHandler(SpotHandler spotHandler) { + this.spotHandler = spotHandler; + } + + public Set getResult() { + return spots.build(); + } + + @Override + public HandlerWithResult> 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); + } + +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/LaunchSpecificationHandler.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/LaunchSpecificationHandler.java new file mode 100644 index 0000000000..a3e14e2540 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/LaunchSpecificationHandler.java @@ -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 { + + @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(); + } + } + +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/PlacementGroupHandler.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/PlacementGroupHandler.java index e466204b6c..8eb7615cef 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/PlacementGroupHandler.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/PlacementGroupHandler.java @@ -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 { private StringBuilder currentText = new StringBuilder(); - @Inject - protected DateService dateService; @Inject @Region String defaultRegion; diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/SpotHandler.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/SpotHandler.java new file mode 100644 index 0000000000..de6d3da33f --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/SpotHandler.java @@ -0,0 +1,75 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 { + 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); + } +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/SpotInstanceHandler.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/SpotInstanceHandler.java new file mode 100644 index 0000000000..c4bde57afe --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/SpotInstanceHandler.java @@ -0,0 +1,125 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 { + 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); + } +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/SpotInstancesHandler.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/SpotInstancesHandler.java new file mode 100644 index 0000000000..d5022fe8b4 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/SpotInstancesHandler.java @@ -0,0 +1,84 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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> { + + private final Builder spotRequests = ImmutableSet. builder(); + private final SpotInstanceHandler spotRequestHandler; + private int itemDepth; + + @Inject + public SpotInstancesHandler(SpotInstanceHandler spotRequestHandler) { + this.spotRequestHandler = spotRequestHandler; + } + + public Set getResult() { + return spotRequests.build(); + } + + @Override + public HandlerWithResult> 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); + } + +} diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/binders/BindLaunchSpecificationToFormParamsTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/binders/BindLaunchSpecificationToFormParamsTest.java new file mode 100644 index 0000000000..589c23c9c5 --- /dev/null +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/binders/BindLaunchSpecificationToFormParamsTest.java @@ -0,0 +1,60 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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()))); + } +} diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/options/DescribeSpotPriceHistoryOptionsTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/options/DescribeSpotPriceHistoryOptionsTest.java new file mode 100644 index 0000000000..717298f8a1 --- /dev/null +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/options/DescribeSpotPriceHistoryOptionsTest.java @@ -0,0 +1,122 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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); + } + +} diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/options/RequestSpotInstancesOptionsTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/options/RequestSpotInstancesOptionsTest.java new file mode 100644 index 0000000000..77fb3851df --- /dev/null +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/options/RequestSpotInstancesOptionsTest.java @@ -0,0 +1,145 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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); + } + +} diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AMIClientLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AMIClientLiveTest.java index c6081b6cad..ec9b684939 100644 --- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AMIClientLiveTest.java +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AMIClientLiveTest.java @@ -100,7 +100,7 @@ public class AMIClientLiveTest { setupCredentials(); Properties overrides = setupProperties(); context = new ComputeServiceContextFactory().createContext(provider, - ImmutableSet. of(new Log4JLoggingModule()), overrides).getProviderSpecificContext(); + ImmutableSet. 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)); } diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/SpotInstanceAsyncClientTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/SpotInstanceAsyncClientTest.java new file mode 100644 index 0000000000..6e1dde535d --- /dev/null +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/SpotInstanceAsyncClientTest.java @@ -0,0 +1,190 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 { + 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> createTypeLiteral() { + return new TypeLiteral>() { + }; + } + +} diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/SpotInstanceClientLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/SpotInstanceClientLiveTest.java new file mode 100644 index 0000000000..ab3b59d96d --- /dev/null +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/SpotInstanceClientLiveTest.java @@ -0,0 +1,207 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 activeTester; + private Set 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. of(new Log4JLoggingModule(), new JschSshClientModule()), overrides); + + client = AWSEC2Client.class.cast(context.getProviderSpecificContext().getApi()); + activeTester = new RetryablePredicate(new SpotInstanceRequestActive(client), + SPOT_DELAY_SECONDS, 1, 1, TimeUnit.SECONDS); + } + + @Test + void testDescribeSpotRequestsInRegion() { + for (String region : Region.DEFAULT_REGIONS) { + SortedSet allResults = ImmutableSortedSet.copyOf(client.getSpotInstanceServices() + .describeSpotInstanceRequestsInRegion(region)); + assertNotNull(allResults); + if (allResults.size() >= 1) { + SpotInstanceRequest request = allResults.last(); + SortedSet 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 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(); + } +} diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/RunInstancesResponseHandlerTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/AWSRunInstancesResponseHandlerTest.java similarity index 98% rename from providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/RunInstancesResponseHandlerTest.java rename to providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/AWSRunInstancesResponseHandlerTest.java index c2e18320de..0e1f4cef9c 100644 --- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/RunInstancesResponseHandlerTest.java +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/AWSRunInstancesResponseHandlerTest.java @@ -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; diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/DescribeSpotPriceHistoryResponseHandlerTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/DescribeSpotPriceHistoryResponseHandlerTest.java new file mode 100644 index 0000000000..23e0d87067 --- /dev/null +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/DescribeSpotPriceHistoryResponseHandlerTest.java @@ -0,0 +1,69 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. 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 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); + } +} diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/SpotInstanceHandlerTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/SpotInstanceHandlerTest.java new file mode 100644 index 0000000000..460b77f6eb --- /dev/null +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/SpotInstanceHandlerTest.java @@ -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. of()).atLeastOnce(); + replay(request); + handler.setContext(request); + } +} diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/SpotInstancesHandlerTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/SpotInstancesHandlerTest.java new file mode 100644 index 0000000000..498f9787ea --- /dev/null +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/SpotInstancesHandlerTest.java @@ -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 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 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. of()).atLeastOnce(); + replay(request); + handler.setContext(request); + } +} diff --git a/providers/aws-ec2/src/test/resources/describe_spot_instance_requests.xml b/providers/aws-ec2/src/test/resources/describe_spot_instance_requests.xml new file mode 100644 index 0000000000..a34b0f63a2 --- /dev/null +++ b/providers/aws-ec2/src/test/resources/describe_spot_instance_requests.xml @@ -0,0 +1,413 @@ + + 7c4dd2bd-106d-4cd3-987c-35ee819180a6 + + + sir-067a4805 + 0.040000 + one-time + cancelled + + ami-595a0a1c + + + default + + + t1.micro + + + false + + + 2011-03-07T20:13:07.000Z + Linux/UNIX + + + sir-aa67d410 + 0.040000 + one-time + cancelled + + ami-595a0a1c + + + default + + + t1.micro + + + false + + + 2011-03-07T20:13:57.000Z + Linux/UNIX + + + sir-32e32810 + 0.010000 + one-time + cancelled + + ami-595a0a1c + + + default + + + t1.micro + + + false + + + 2011-03-07T20:15:52.000Z + Linux/UNIX + + + sir-46a36210 + 0.010000 + one-time + cancelled + 2011-03-07T20:20:00.000Z + foo + azfoo + + ami-595a0a1c + default + + + quick-start-1 + + + t1.micro + + + true + + + 2011-03-07T20:18:25.000Z + Linux/UNIX + + + sir-91780010 + 0.010000 + one-time + cancelled + 2011-03-07T20:20:00.000Z + foo + azfoo + + ami-595a0a1c + default + + + quick-start-1 + + + t1.micro + + + true + + + 2011-03-07T20:18:25.000Z + Linux/UNIX + + + sir-6f1fa605 + 0.001000 + one-time + cancelled + + ami-595a0a1c + + + default + + + t1.micro + + + false + + + 2011-03-07T20:19:27.000Z + Linux/UNIX + + + sir-a33eee10 + 0.001000 + one-time + cancelled + + ami-595a0a1c + + + default + + + t1.micro + + + false + + + 2011-03-07T20:21:16.000Z + Linux/UNIX + + + sir-aa690410 + 0.001000 + one-time + cancelled + + ami-595a0a1c + + + default + + + t1.micro + + + false + + + 2011-03-07T20:21:52.000Z + Linux/UNIX + + + sir-99ba4e06 + 0.010000 + one-time + cancelled + 2011-03-07T20:26:00.000Z + doo + dooo + + ami-595a0a1c + default + + + quick-start-1 + + + t1.micro + + + true + + + 2011-03-07T20:24:30.000Z + Linux/UNIX + + + sir-a617c406 + 0.010000 + one-time + cancelled + 2011-03-07T20:26:00.000Z + doo + dooo + + ami-595a0a1c + default + + + quick-start-1 + + + t1.micro + + + true + + + 2011-03-07T20:24:30.000Z + Linux/UNIX + + + sir-2147a405 + 0.001000 + one-time + cancelled + + ami-595a0a1c + + + default + + + t1.micro + + + false + + + 2011-03-07T20:25:19.000Z + Linux/UNIX + + + sir-c441c805 + 0.001000 + one-time + cancelled + + ami-595a0a1c + + + default + + + t1.micro + + + false + + + 2011-03-07T20:29:09.000Z + Linux/UNIX + + + sir-4658fe10 + 0.010000 + one-time + cancelled + 2011-03-07T21:10:00.000Z + check3 + check3 + + ami-595a0a1c + default + + + quick-start-1 + + + t1.micro + + + false + + + 2011-03-07T20:31:34.000Z + Linux/UNIX + + + sir-49a3ce10 + 0.010000 + one-time + cancelled + 2011-03-07T21:10:00.000Z + check3 + check3 + + ami-595a0a1c + default + + + quick-start-1 + + + t1.micro + + + false + + + 2011-03-07T20:31:34.000Z + Linux/UNIX + + + sir-91b30610 + 0.010000 + one-time + cancelled + 2011-03-07T21:10:00.000Z + check3 + check3 + + ami-595a0a1c + default + + + quick-start-1 + + + t1.micro + + + false + + + 2011-03-07T20:31:34.000Z + Linux/UNIX + + + sir-d8561606 + 0.001000 + one-time + cancelled + + ami-595a0a1c + + + default + + + t1.micro + + + false + + + 2011-03-07T20:34:10.000Z + Linux/UNIX + + + sir-4cdaa406 + 0.001000 + persistent + cancelled + 2011-03-07T22:25:00.000Z + + ami-595a0a1c + default + + + quick-start-1 + + + t1.micro + + + false + + + 2011-03-07T22:23:19.000Z + Linux/UNIX + + + sir-e19f2206 + 0.001000 + one-time + open + + ami-595a0a1c + + + default + + + t1.micro + + + false + + + 2011-03-07T22:32:50.000Z + Linux/UNIX + + + \ No newline at end of file diff --git a/providers/aws-ec2/src/test/resources/describe_spot_price_history.xml b/providers/aws-ec2/src/test/resources/describe_spot_price_history.xml new file mode 100644 index 0000000000..b6fd33692c --- /dev/null +++ b/providers/aws-ec2/src/test/resources/describe_spot_price_history.xml @@ -0,0 +1,24 @@ + + + 99777a75-2a2b-4296-a305-650c442d2d63 + + + t1.micro + SUSE Linux + 0.013000 + 2011-03-07T12:17:19.000Z + + + m1.large + Linux/UNIX + 0.119000 + 2011-03-07T16:29:16.000Z + + + t1.micro + Windows + 0.013000 + 2011-03-07T17:56:54.000Z + + + \ No newline at end of file diff --git a/providers/aws-ec2/src/test/resources/request_spot_instances-ebs.xml b/providers/aws-ec2/src/test/resources/request_spot_instances-ebs.xml new file mode 100644 index 0000000000..e95d8d948b --- /dev/null +++ b/providers/aws-ec2/src/test/resources/request_spot_instances-ebs.xml @@ -0,0 +1,47 @@ + + + 02401e8e-a4f5-4285-8ea8-6d742fbaadd8 + + + sir-228e6406 + 0.001000 + one-time + open + + ami-595a0a1c + + + default + + + m1.large + + + /dev/sda1 + + 1 + true + + + + /dev/sda3 + vre1 + + + /dev/sda2 + + snap-1ea27576 + 1 + true + + + + + false + + + 2011-03-08T03:30:36.000Z + Linux/UNIX + + + \ No newline at end of file diff --git a/providers/aws-ec2/src/test/resources/request_spot_instances.xml b/providers/aws-ec2/src/test/resources/request_spot_instances.xml new file mode 100644 index 0000000000..3df9689cd0 --- /dev/null +++ b/providers/aws-ec2/src/test/resources/request_spot_instances.xml @@ -0,0 +1,93 @@ + + + 2ffc645f-6835-4d23-bd18-f6f53c253067 + + + sir-7c74f805 + 0.001000 + one-time + open + + ami-595a0a1c + + + default + + + t1.micro + + + /dev/sda1 + + 120 + true + + + + + false + + + 2011-03-08T02:36:32.000Z + Linux/UNIX + + + sir-78ca7605 + 0.001000 + one-time + open + + ami-595a0a1c + + + default + + + t1.micro + + + /dev/sda1 + + 120 + true + + + + + false + + + 2011-03-08T02:36:32.000Z + Linux/UNIX + + + sir-7e0f6005 + 0.001000 + one-time + open + + ami-595a0a1c + + + default + + + t1.micro + + + /dev/sda1 + + 120 + true + + + + + false + + + 2011-03-08T02:36:32.000Z + Linux/UNIX + + + \ No newline at end of file