diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/compute/internal/EC2TemplateBuilderImpl.java b/apis/ec2/src/main/java/org/jclouds/ec2/compute/internal/EC2TemplateBuilderImpl.java index ae2e275150..a2f87d1733 100644 --- a/apis/ec2/src/main/java/org/jclouds/ec2/compute/internal/EC2TemplateBuilderImpl.java +++ b/apis/ec2/src/main/java/org/jclouds/ec2/compute/internal/EC2TemplateBuilderImpl.java @@ -69,6 +69,8 @@ public class EC2TemplateBuilderImpl extends TemplateBuilderImpl { eTo.securityGroups(eFrom.getGroupIds()); if (eFrom.getKeyPair() != null) eTo.keyPair(eFrom.getKeyPair()); + if (eFrom.getBlockDeviceMappings().size() > 0) + eTo.blockDeviceMappings(eFrom.getBlockDeviceMappings()); if (!eFrom.shouldAutomaticallyCreateKeyPair()) eTo.noKeyPair(); if (eFrom.getUserData() != null) 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 f776c2c14d..858575bcc9 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 @@ -24,7 +24,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import java.util.Arrays; -import java.util.HashSet; import java.util.Set; import javax.annotation.Nullable; @@ -123,34 +122,34 @@ public class EC2TemplateOptions extends TemplateOptions { * Specifies the block device mappings to be used to run the instance */ public EC2TemplateOptions mapEBSSnapshotToDeviceName(String deviceName, String snapshotId, - @Nullable Integer sizeInGib, @Nullable Boolean deleteOnTermination) { + @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"); - Set mappings = new HashSet(); + com.google.common.collect.ImmutableSet.Builder mappings = ImmutableSet + . builder(); mappings.addAll(blockDeviceMappings); MapEBSSnapshotToDevice mapping = new MapEBSSnapshotToDevice(deviceName, snapshotId, sizeInGib, deleteOnTermination); mappings.add(mapping); - blockDeviceMappings = ImmutableSet.copyOf(mappings); + blockDeviceMappings = mappings.build(); return this; } /** * Specifies the block device mappings to be used to run the instance */ - public EC2TemplateOptions mapNewVolumeToDeviceName(String deviceName, Integer sizeInGib, - @Nullable Boolean deleteOnTermination) { + public EC2TemplateOptions mapNewVolumeToDeviceName(String deviceName, int sizeInGib, boolean deleteOnTermination) { checkNotNull(deviceName, "deviceName cannot be null"); Preconditions2.checkNotEmpty(deviceName, "deviceName must be non-empty"); - checkNotNull(sizeInGib, "sizeInGib cannot be null"); - Set mappings = new HashSet(); + com.google.common.collect.ImmutableSet.Builder mappings = ImmutableSet + . builder(); mappings.addAll(blockDeviceMappings); MapNewVolumeToDevice mapping = new MapNewVolumeToDevice(deviceName, sizeInGib, deleteOnTermination); mappings.add(mapping); - blockDeviceMappings = ImmutableSet.copyOf(mappings); + blockDeviceMappings = mappings.build(); return this; } @@ -163,11 +162,12 @@ public class EC2TemplateOptions extends TemplateOptions { checkNotNull(virtualName, "virtualName cannot be null"); Preconditions2.checkNotEmpty(virtualName, "virtualName must be non-empty"); - Set mappings = new HashSet(); + com.google.common.collect.ImmutableSet.Builder mappings = ImmutableSet + . builder(); mappings.addAll(blockDeviceMappings); MapEphemeralDeviceToDevice mapping = new MapEphemeralDeviceToDevice(deviceName, virtualName); mappings.add(mapping); - blockDeviceMappings = ImmutableSet.copyOf(mappings); + blockDeviceMappings = mappings.build(); return this; } @@ -178,11 +178,12 @@ public class EC2TemplateOptions extends TemplateOptions { checkNotNull(deviceName, "deviceName cannot be null"); Preconditions2.checkNotEmpty(deviceName, "deviceName must be non-empty"); - Set mappings = new HashSet(); + com.google.common.collect.ImmutableSet.Builder mappings = ImmutableSet + . builder(); mappings.addAll(blockDeviceMappings); UnmapDeviceNamed mapping = new UnmapDeviceNamed(deviceName); mappings.add(mapping); - blockDeviceMappings = ImmutableSet.copyOf(mappings); + blockDeviceMappings = mappings.build(); return this; } @@ -195,6 +196,47 @@ public class EC2TemplateOptions extends TemplateOptions { } public static class Builder { + /** + * @see EC2TemplateOptions#blockDeviceMappings + */ + public static EC2TemplateOptions blockDeviceMappings(Set blockDeviceMappings) { + EC2TemplateOptions options = new EC2TemplateOptions(); + return options.blockDeviceMappings(blockDeviceMappings); + } + + /** + * @see EC2TemplateOptions#mapEBSSnapshotToDeviceName + */ + public static EC2TemplateOptions mapEBSSnapshotToDeviceName(String deviceName, String snapshotId, + @Nullable Integer sizeInGib, boolean deleteOnTermination) { + EC2TemplateOptions options = new EC2TemplateOptions(); + return options.mapEBSSnapshotToDeviceName(deviceName, snapshotId, sizeInGib, deleteOnTermination); + } + + /** + * @see EC2TemplateOptions#mapNewVolumeToDeviceName + */ + public static EC2TemplateOptions mapNewVolumeToDeviceName(String deviceName, int sizeInGib, + boolean deleteOnTermination) { + EC2TemplateOptions options = new EC2TemplateOptions(); + return options.mapNewVolumeToDeviceName(deviceName, sizeInGib, deleteOnTermination); + } + + /** + * @see EC2TemplateOptions#mapEphemeralDeviceToDeviceName + */ + public static EC2TemplateOptions mapEphemeralDeviceToDeviceName(String deviceName, String virtualName) { + EC2TemplateOptions options = new EC2TemplateOptions(); + return options.mapEphemeralDeviceToDeviceName(deviceName, virtualName); + } + + /** + * @see EC2TemplateOptions#unmapDeviceNamed + */ + public static EC2TemplateOptions unmapDeviceNamed(String deviceName) { + EC2TemplateOptions options = new EC2TemplateOptions(); + return options.unmapDeviceNamed(deviceName); + } /** * @see EC2TemplateOptions#securityGroups(Iterable) @@ -494,8 +536,7 @@ public class EC2TemplateOptions extends TemplateOptions { @Override public String toString() { - - return "EC2TemplateOptions [groupIds=" + groupIds + ", keyPair=" + keyPair + ", noKeyPair=" + noKeyPair - + ", userData=" + Arrays.toString(userData) + ", blockDeviceMappings=" + blockDeviceMappings + "]"; + return "[groupIds=" + groupIds + ", keyPair=" + keyPair + ", noKeyPair=" + noKeyPair + ", userData=" + + Arrays.toString(userData) + ", blockDeviceMappings=" + blockDeviceMappings + "]"; } } diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.java b/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.java index 835dbd4973..26b35e34e7 100644 --- a/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.java +++ b/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.java @@ -79,21 +79,23 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions { String keyPairName = createNewKeyPairUnlessUserSpecifiedOtherwise(region, tag, template.getOptions()); addSecurityGroups(region, tag, template, instanceOptions); + if (template.getOptions() instanceof EC2TemplateOptions) { - if (keyPairName != null) - instanceOptions.withKeyName(keyPairName); + if (keyPairName != null) + instanceOptions.withKeyName(keyPairName); - byte[] userData = EC2TemplateOptions.class.cast(template.getOptions()).getUserData(); + byte[] userData = EC2TemplateOptions.class.cast(template.getOptions()).getUserData(); - if (userData != null) - instanceOptions.withUserData(userData); + if (userData != null) + instanceOptions.withUserData(userData); - Set blockDeviceMappings = EC2TemplateOptions.class.cast(template.getOptions()) - .getBlockDeviceMappings(); - if (blockDeviceMappings != null && blockDeviceMappings.size() > 0) { - checkState("ebs".equals(template.getImage().getUserMetadata().get("rootDeviceType")), - "BlockDeviceMapping only available on ebs boot"); - instanceOptions.withBlockDeviceMappings(blockDeviceMappings); + Set blockDeviceMappings = EC2TemplateOptions.class.cast(template.getOptions()) + .getBlockDeviceMappings(); + if (blockDeviceMappings.size() > 0) { + checkState("ebs".equals(template.getImage().getUserMetadata().get("rootDeviceType")), + "BlockDeviceMapping only available on ebs boot"); + instanceOptions.withBlockDeviceMappings(blockDeviceMappings); + } } return instanceOptions; } diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/domain/BlockDevice.java b/apis/ec2/src/main/java/org/jclouds/ec2/domain/BlockDevice.java index 3a98726d48..a0765ade8b 100644 --- a/apis/ec2/src/main/java/org/jclouds/ec2/domain/BlockDevice.java +++ b/apis/ec2/src/main/java/org/jclouds/ec2/domain/BlockDevice.java @@ -37,7 +37,6 @@ public class BlockDevice { private final boolean deleteOnTermination; public BlockDevice(String volumeId, Status attachmentStatus, Date attachTime, boolean deleteOnTermination) { - super(); this.volumeId = volumeId; this.attachmentStatus = attachmentStatus; this.attachTime = attachTime; 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 94364d10e6..0e6c3563f8 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 @@ -42,15 +42,15 @@ public class BlockDeviceMapping { private static final Integer VOLUME_SIZE_MIN_VALUE = 1; private static final Integer VOLUME_SIZE_MAX_VALUE = 1000; - public BlockDeviceMapping(String deviceName, @Nullable String virtualName, @Nullable String snapshotId, - @Nullable Integer sizeInGib, @Nullable Boolean noDevice, @Nullable Boolean deleteOnTermination) { + BlockDeviceMapping(String deviceName, @Nullable String virtualName, @Nullable String snapshotId, + @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; @@ -88,7 +88,12 @@ public class BlockDeviceMapping { public int hashCode() { final int prime = 31; int result = 1; + result = prime * result + ((deleteOnTermination == null) ? 0 : deleteOnTermination.hashCode()); result = prime * result + ((deviceName == null) ? 0 : deviceName.hashCode()); + result = prime * result + ((noDevice == null) ? 0 : noDevice.hashCode()); + result = prime * result + ((sizeInGib == null) ? 0 : sizeInGib.hashCode()); + result = prime * result + ((snapshotId == null) ? 0 : snapshotId.hashCode()); + result = prime * result + ((virtualName == null) ? 0 : virtualName.hashCode()); return result; } @@ -101,24 +106,49 @@ public class BlockDeviceMapping { if (getClass() != obj.getClass()) return false; BlockDeviceMapping other = (BlockDeviceMapping) obj; + if (deleteOnTermination == null) { + if (other.deleteOnTermination != null) + return false; + } else if (!deleteOnTermination.equals(other.deleteOnTermination)) + return false; if (deviceName == null) { if (other.deviceName != null) return false; } else if (!deviceName.equals(other.deviceName)) return false; + if (noDevice == null) { + if (other.noDevice != null) + return false; + } else if (!noDevice.equals(other.noDevice)) + return false; + if (sizeInGib == null) { + if (other.sizeInGib != null) + return false; + } else if (!sizeInGib.equals(other.sizeInGib)) + return false; + if (snapshotId == null) { + if (other.snapshotId != null) + return false; + } else if (!snapshotId.equals(other.snapshotId)) + return false; + if (virtualName == null) { + if (other.virtualName != null) + return false; + } else if (!virtualName.equals(other.virtualName)) + return false; return true; } @Override public String toString() { - return "BlockDeviceMapping [deviceName=" + deviceName + ", virtualName=" + virtualName + ", snapshotId=" - + snapshotId + ", sizeInGib=" + sizeInGib + ", noDevice=" + noDevice + ", deleteOnTermination=" - + deleteOnTermination + "]"; + return "[deviceName=" + deviceName + ", virtualName=" + virtualName + ", snapshotId=" + snapshotId + + ", 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"); 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 0e35548e78..30c166afdc 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 @@ -153,7 +153,7 @@ public class RunInstancesOptions extends BaseEC2RequestOptions { public RunInstancesOptions withBlockDeviceMappings(Set mappings) { int i = 1; - for (BlockDeviceMapping mapping : mappings) { + for (BlockDeviceMapping mapping : checkNotNull(mappings, "mappings")) { checkNotNull(mapping.getDeviceName(), "deviceName"); formParameters.put(String.format("BlockDeviceMapping.%d.DeviceName", i), mapping.getDeviceName()); if (mapping.getVirtualName() != null) diff --git a/apis/ec2/src/test/java/org/jclouds/ec2/compute/EC2ComputeServiceLiveTest.java b/apis/ec2/src/test/java/org/jclouds/ec2/compute/EC2ComputeServiceLiveTest.java index fb17edaca1..46c7bd7cf1 100644 --- a/apis/ec2/src/test/java/org/jclouds/ec2/compute/EC2ComputeServiceLiveTest.java +++ b/apis/ec2/src/test/java/org/jclouds/ec2/compute/EC2ComputeServiceLiveTest.java @@ -22,7 +22,6 @@ package org.jclouds.ec2.compute; import static org.jclouds.compute.util.ComputeServiceUtils.getCores; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; -import static org.testng.Assert.assertNotNull; import java.util.Map; import java.util.Set; @@ -34,10 +33,12 @@ import org.jclouds.compute.domain.Template; import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.predicates.NodePredicates; import org.jclouds.domain.Credentials; +import org.jclouds.domain.Location; +import org.jclouds.domain.LocationScope; import org.jclouds.ec2.EC2Client; import org.jclouds.ec2.compute.options.EC2TemplateOptions; -import org.jclouds.ec2.domain.AvailabilityZone; import org.jclouds.ec2.domain.BlockDevice; +import org.jclouds.ec2.domain.InstanceType; import org.jclouds.ec2.domain.IpProtocol; import org.jclouds.ec2.domain.KeyPair; import org.jclouds.ec2.domain.RunningInstance; @@ -51,6 +52,7 @@ import org.jclouds.ec2.services.SecurityGroupClient; import org.jclouds.ssh.jsch.config.JschSshClientModule; import org.testng.annotations.Test; +import com.google.common.base.Predicate; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; @@ -76,7 +78,7 @@ public class EC2ComputeServiceLiveTest extends BaseComputeServiceLiveTest { public void testImagesResolveCorrectly() { Template defaultTemplate = client.templateBuilder().build(); assertEquals(defaultTemplate.getImage().getId(), defaultTemplate.getImage().getLocation().getId() + "/" - + defaultTemplate.getImage().getProviderId()); + + defaultTemplate.getImage().getProviderId()); Template byId = client.templateBuilder().imageId(defaultTemplate.getImage().getId()).build(); assertEquals(byId.getImage(), defaultTemplate.getImage()); } @@ -97,13 +99,13 @@ public class EC2ComputeServiceLiveTest extends BaseComputeServiceLiveTest { @Test(enabled = true, dependsOnMethods = "testCompareSizes") public void testExtendedOptionsAndLogin() throws Exception { SecurityGroupClient securityGroupClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi()) - .getSecurityGroupServices(); + .getSecurityGroupServices(); KeyPairClient keyPairClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi()) - .getKeyPairServices(); + .getKeyPairServices(); InstanceClient instanceClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi()) - .getInstanceServices(); + .getInstanceServices(); String tag = this.tag + "o"; @@ -136,17 +138,17 @@ public class EC2ComputeServiceLiveTest extends BaseComputeServiceLiveTest { assertEquals(instance.getKeyName(), tag); // make sure we made our dummy group and also let in the user's group - assertEquals(Sets.newTreeSet(instance.getGroupIds()), - ImmutableSortedSet. of("jclouds#" + tag + "#" + instance.getRegion(), tag)); + assertEquals(Sets.newTreeSet(instance.getGroupIds()), ImmutableSortedSet. of("jclouds#" + tag + "#" + + instance.getRegion(), tag)); // make sure our dummy group has no rules SecurityGroup group = Iterables.getOnlyElement(securityGroupClient.describeSecurityGroupsInRegion(null, - "jclouds#" + tag + "#" + instance.getRegion())); + "jclouds#" + tag + "#" + instance.getRegion())); assert group.getIpPermissions().size() == 0 : group; // try to run a script with the original keyPair - runScriptWithCreds(tag, first.getOperatingSystem(), - new Credentials(first.getCredentials().identity, result.getKeyMaterial())); + runScriptWithCreds(tag, first.getOperatingSystem(), new Credentials(first.getCredentials().identity, result + .getKeyMaterial())); } finally { client.destroyNodesMatching(NodePredicates.withTag(tag)); @@ -159,243 +161,86 @@ public class EC2ComputeServiceLiveTest extends BaseComputeServiceLiveTest { } } - @Test(enabled = true, dependsOnMethods = "testCompareSizes") - public void testExtendedOptionsNoKeyPair() throws Exception { - SecurityGroupClient securityGroupClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi()) - .getSecurityGroupServices(); - - KeyPairClient keyPairClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi()) - .getKeyPairServices(); - - InstanceClient instanceClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi()) - .getInstanceServices(); - - String tag = this.tag + "k"; - - TemplateOptions options = client.templateOptions(); - - options.as(EC2TemplateOptions.class).securityGroups(tag); - options.as(EC2TemplateOptions.class).noKeyPair(); - - String startedId = null; - try { - cleanupExtendedStuff(securityGroupClient, keyPairClient, tag); - - // create the security group - securityGroupClient.createSecurityGroupInRegion(null, tag, tag); - - Set nodes = client.runNodesWithTag(tag, 1, options); - Credentials creds = nodes.iterator().next().getCredentials(); - assert creds == null; - - startedId = Iterables.getOnlyElement(nodes).getProviderId(); - - RunningInstance instance = getInstance(instanceClient, startedId); - - assertEquals(instance.getKeyName(), null); - - // make sure we made our dummy group and also let in the user's group - assertEquals(Sets.newTreeSet(instance.getGroupIds()), - ImmutableSortedSet. of(tag, String.format("jclouds#%s#%s", tag, instance.getRegion()))); - - // make sure our dummy group has no rules - SecurityGroup group = Iterables.getOnlyElement(securityGroupClient.describeSecurityGroupsInRegion(null, - String.format("jclouds#%s#%s", tag, instance.getRegion()))); - assert group.getIpPermissions().size() == 0 : group; - - } finally { - client.destroyNodesMatching(NodePredicates.withTag(tag)); - if (startedId != null) { - // ensure we didn't delete these resources! - assertEquals(securityGroupClient.describeSecurityGroupsInRegion(null, tag).size(), 1); - } - cleanupExtendedStuff(securityGroupClient, keyPairClient, tag); - } - } - + /** + * Note we cannot use the micro size as it has no ephemeral space. + */ @Test(enabled = true) - public void testMapNewVolumeToDeviceName() throws Exception { - SecurityGroupClient securityGroupClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi()) - .getSecurityGroupServices(); - - KeyPairClient keyPairClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi()) - .getKeyPairServices(); + public void testMapEBS() throws Exception { InstanceClient instanceClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi()) - .getInstanceServices(); + .getInstanceServices(); - String tag = this.tag + "BDM1"; - int volumeSize = 120; - TemplateOptions options = client.templateOptions(); - - options.as(EC2TemplateOptions.class).securityGroups(tag); - options.as(EC2TemplateOptions.class).noKeyPair(); - options.as(EC2TemplateOptions.class).mapNewVolumeToDeviceName("/dev/sda1", volumeSize, true); - - String startedId = null; - try { - cleanupExtendedStuff(securityGroupClient, keyPairClient, tag); - - // create the security group - securityGroupClient.createSecurityGroupInRegion(null, tag, tag); - - Set nodes = client.runNodesWithTag(tag, 1, options); - Credentials creds = nodes.iterator().next().getCredentials(); - assert creds == null; - - NodeMetadata node = nodes.iterator().next(); - startedId = node.getId(); - - Map devices = instanceClient - .getBlockDeviceMappingForInstanceInRegion(node.getLocation() - .getParent().getId(), node.getProviderId()); - - BlockDevice device = devices.get("/dev/sda1"); - //check delete on termination - assertTrue(device.isDeleteOnTermination()); - ElasticBlockStoreClient ebsClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi()) - .getElasticBlockStoreServices(); - - Set volumes = ebsClient.describeVolumesInRegion(node - .getLocation().getParent().getId(), device.getVolumeId()); - // check volume size - assertEquals(volumeSize, volumes.iterator().next().getSize()); - - } finally { - client.destroyNodesMatching(NodePredicates.withTag(tag)); - if (startedId != null) { - // ensure we didn't delete these resources! - assertEquals(securityGroupClient.describeSecurityGroupsInRegion(null, tag).size(), 1); - } - cleanupExtendedStuff(securityGroupClient, keyPairClient, tag); - } - } - - @Test(enabled = true) - public void testMapEBSSnapshotToDeviceName() throws Exception { - SecurityGroupClient securityGroupClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi()) - .getSecurityGroupServices(); - - KeyPairClient keyPairClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi()) - .getKeyPairServices(); - - InstanceClient instanceClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi()) - .getInstanceServices(); - ElasticBlockStoreClient ebsClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi()) - .getElasticBlockStoreServices(); - //create snapshot - Volume volume = ebsClient.createVolumeInAvailabilityZone(AvailabilityZone.US_EAST_1A, 4); + .getElasticBlockStoreServices(); + + String tag = this.tag + "e"; + int volumeSize = 8; + + Location zone = Iterables.find(context.getComputeService().listAssignableLocations(), new Predicate() { + + @Override + public boolean apply(Location arg0) { + return arg0.getScope() == LocationScope.ZONE; + } + + }); + + // create volume only to make a snapshot + Volume volume = ebsClient.createVolumeInAvailabilityZone(zone.getId(), 4); Snapshot snapshot = ebsClient.createSnapshotInRegion(volume.getRegion(), volume.getId()); + ebsClient.deleteVolumeInRegion(volume.getRegion(), volume.getId()); - String tag = this.tag + "BDM2"; - int volumeSize = 120; - TemplateOptions options = client.templateOptions(); + Template template = context.getComputeService().templateBuilder().locationId(volume.getRegion()).hardwareId( + InstanceType.M1_SMALL).imageDescriptionMatches(".*ebs.*").build(); + + template.getOptions().as(EC2TemplateOptions.class)// + // .unmapDeviceNamed("/dev/foo) + .mapEphemeralDeviceToDeviceName("/dev/sdm", "ephemeral0")// + .mapNewVolumeToDeviceName("/dev/sdn", volumeSize, true)// + .mapEBSSnapshotToDeviceName("/dev/sdo", snapshot.getId(), volumeSize, true); - options.as(EC2TemplateOptions.class).securityGroups(tag); - options.as(EC2TemplateOptions.class).noKeyPair(); - options.as(EC2TemplateOptions.class).mapEBSSnapshotToDeviceName("/dev/sda1", snapshot.getId(), 120, true); - - String startedId = null; try { - cleanupExtendedStuff(securityGroupClient, keyPairClient, tag); + NodeMetadata node = Iterables.getOnlyElement(client.runNodesWithTag(tag, 1, template)); - // create the security group - securityGroupClient.createSecurityGroupInRegion(null, tag, tag); + // TODO figure out how to validate the ephemeral drive. perhaps with df -k? - Set nodes = client.runNodesWithTag(tag, 1, options); - Credentials creds = nodes.iterator().next().getCredentials(); - assert creds == null; + Map devices = instanceClient.getBlockDeviceMappingForInstanceInRegion(node.getLocation() + .getParent().getId(), node.getProviderId()); - NodeMetadata node = nodes.iterator().next(); - - Map devices = instanceClient - .getBlockDeviceMappingForInstanceInRegion(node.getLocation() - .getParent().getId(), node.getProviderId()); - - BlockDevice device = devices.get("/dev/sda1"); - //check delete on termination + BlockDevice device = devices.get("/dev/sdn"); + // check delete on termination assertTrue(device.isDeleteOnTermination()); - - Set volumes = ebsClient.describeVolumesInRegion(node - .getLocation().getParent().getId(), device.getVolumeId()); - // check volume size - assertEquals(volumeSize, volumes.iterator().next().getSize()); - //check volume's snapshot id - assertEquals(snapshot.getId(), volumes.iterator().next().getSnapshotId()); + volume = Iterables.getOnlyElement(ebsClient.describeVolumesInRegion(node.getLocation().getParent().getId(), + device.getVolumeId())); + // check volume size + assertEquals(volumeSize, volume.getSize()); + + device = devices.get("/dev/sdo"); + // check delete on termination + assertTrue(device.isDeleteOnTermination()); + + volume = Iterables.getOnlyElement(ebsClient.describeVolumesInRegion(node.getLocation().getParent().getId(), + device.getVolumeId())); + // check volume size + assertEquals(volumeSize, volume.getSize()); + // check volume's snapshot id + assertEquals(snapshot.getId(), volume.getSnapshotId()); } finally { client.destroyNodesMatching(NodePredicates.withTag(tag)); ebsClient.deleteSnapshotInRegion(snapshot.getRegion(), snapshot.getId()); - ebsClient.deleteVolumeInRegion(volume.getRegion(), volume.getId()); - if (startedId != null) { - // ensure we didn't delete these resources! - assertEquals(securityGroupClient.describeSecurityGroupsInRegion(null, tag).size(), 1); - } - cleanupExtendedStuff(securityGroupClient, keyPairClient, tag); } } - - @Test(enabled = true) - public void testMapEphemeralDeviceToDeviceName() throws Exception { - SecurityGroupClient securityGroupClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi()) - .getSecurityGroupServices(); - - KeyPairClient keyPairClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi()) - .getKeyPairServices(); - - InstanceClient instanceClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi()) - .getInstanceServices(); - - String tag = this.tag + "BDM3"; - - TemplateOptions options = client.templateOptions(); - - options.as(EC2TemplateOptions.class).securityGroups(tag); - options.as(EC2TemplateOptions.class).noKeyPair(); - options.as(EC2TemplateOptions.class).mapEphemeralDeviceToDeviceName("/dev/sdh", "ephemeral0"); - - String startedId = null; - try { - cleanupExtendedStuff(securityGroupClient, keyPairClient, tag); - - // create the security group - securityGroupClient.createSecurityGroupInRegion(null, tag, tag); - - Set nodes = client.runNodesWithTag(tag, 1, options); - Credentials creds = nodes.iterator().next().getCredentials(); - assert creds == null; - - NodeMetadata node = nodes.iterator().next(); - startedId = node.getId(); - - Map devices = instanceClient - .getBlockDeviceMappingForInstanceInRegion(node.getLocation() - .getParent().getId(), node.getProviderId()); - - BlockDevice device = devices.get("/dev/sdh"); - assertNotNull(device); - - } finally { - client.destroyNodesMatching(NodePredicates.withTag(tag)); - if (startedId != null) { - // ensure we didn't delete these resources! - assertEquals(securityGroupClient.describeSecurityGroupsInRegion(null, tag).size(), 1); - } - cleanupExtendedStuff(securityGroupClient, keyPairClient, tag); - } - } - protected RunningInstance getInstance(InstanceClient instanceClient, String id) { RunningInstance instance = Iterables.getOnlyElement(Iterables.getOnlyElement(instanceClient - .describeInstancesInRegion(null, id))); + .describeInstancesInRegion(null, id))); return instance; } protected void cleanupExtendedStuff(SecurityGroupClient securityGroupClient, KeyPairClient keyPairClient, String tag) - throws InterruptedException { + throws InterruptedException { try { for (SecurityGroup group : securityGroupClient.describeSecurityGroupsInRegion(null)) if (group.getName().startsWith("jclouds#" + tag) || group.getName().equals(tag)) { diff --git a/apis/ec2/src/test/java/org/jclouds/ec2/options/RunInstancesOptionsTest.java b/apis/ec2/src/test/java/org/jclouds/ec2/options/RunInstancesOptionsTest.java index 86671e087d..4f82afecd5 100644 --- a/apis/ec2/src/test/java/org/jclouds/ec2/options/RunInstancesOptionsTest.java +++ b/apis/ec2/src/test/java/org/jclouds/ec2/options/RunInstancesOptionsTest.java @@ -29,14 +29,14 @@ import static org.jclouds.ec2.options.RunInstancesOptions.Builder.withUserData; import static org.testng.Assert.assertEquals; import java.util.Collections; -import java.util.HashSet; -import java.util.Set; import org.jclouds.ec2.domain.BlockDeviceMapping; import org.jclouds.ec2.domain.InstanceType; import org.jclouds.http.options.HttpRequestOptions; import org.testng.annotations.Test; +import com.google.common.collect.ImmutableSet; + /** * Tests possible uses of RunInstancesOptions and RunInstancesOptions.Builder.* * @@ -213,11 +213,9 @@ public class RunInstancesOptionsTest { @Test public void testWithBlockDeviceMapping() { - RunInstancesOptions options = new RunInstancesOptions(); - BlockDeviceMapping mapping = new BlockDeviceMapping("/dev/sda1", null, null, 120, null, true); - Set mappings = new HashSet(); - mappings.add(mapping); - options.withBlockDeviceMappings(mappings); + BlockDeviceMapping mapping = new BlockDeviceMapping.MapNewVolumeToDevice("/dev/sda1", 120, true); + RunInstancesOptions options = new RunInstancesOptions().withBlockDeviceMappings(ImmutableSet + . of(mapping)); assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.DeviceName"), Collections .singletonList("/dev/sda1")); assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.VolumeSize"), Collections @@ -234,10 +232,9 @@ public class RunInstancesOptionsTest { @Test public void testWithBlockDeviceMappingStatic() { - BlockDeviceMapping mapping = new BlockDeviceMapping("/dev/sda1", null, null, 120, null, true); - Set mappings = new HashSet(); - mappings.add(mapping); - RunInstancesOptions options = withBlockDeviceMappings(mappings); + BlockDeviceMapping mapping = new BlockDeviceMapping.MapNewVolumeToDevice("/dev/sda1", 120, true); + RunInstancesOptions options = withBlockDeviceMappings(ImmutableSet + . of(mapping)); assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.DeviceName"), Collections .singletonList("/dev/sda1")); assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.VolumeSize"), Collections diff --git a/apis/eucalyptus/src/test/java/org/jclouds/eucalyptus/compute/EucalyptusComputeServiceLiveTest.java b/apis/eucalyptus/src/test/java/org/jclouds/eucalyptus/compute/EucalyptusComputeServiceLiveTest.java index 48d600754d..74068e26c4 100644 --- a/apis/eucalyptus/src/test/java/org/jclouds/eucalyptus/compute/EucalyptusComputeServiceLiveTest.java +++ b/apis/eucalyptus/src/test/java/org/jclouds/eucalyptus/compute/EucalyptusComputeServiceLiveTest.java @@ -41,18 +41,6 @@ public class EucalyptusComputeServiceLiveTest extends EC2ComputeServiceLiveTest tag = "eu"; } - @Override - @Test(enabled = false) - public void testExtendedOptionsAndLogin() throws Exception { - // euc does not support monitoring - } - - @Override - @Test(enabled = false) - public void testExtendedOptionsNoKeyPair() throws Exception { - // euc does not support multiple security groups - } - @Override protected void assertDefaultWorks() { Template defaultTemplate = client.templateBuilder().build(); diff --git a/core/src/main/java/org/jclouds/location/functions/ZoneToEndpoint.java b/core/src/main/java/org/jclouds/location/functions/ZoneToEndpoint.java index e8e76b6ef9..71cef367f0 100644 --- a/core/src/main/java/org/jclouds/location/functions/ZoneToEndpoint.java +++ b/core/src/main/java/org/jclouds/location/functions/ZoneToEndpoint.java @@ -19,9 +19,12 @@ package org.jclouds.location.functions; +import static com.google.common.base.Preconditions.checkArgument; + import java.net.URI; import java.util.Map; +import javax.annotation.Nullable; import javax.inject.Inject; import javax.inject.Singleton; @@ -35,6 +38,7 @@ import com.google.common.base.Function; */ @Singleton public class ZoneToEndpoint implements Function { + private final Map zoneToEndpoint; @Inject @@ -42,8 +46,9 @@ public class ZoneToEndpoint implements Function { this.zoneToEndpoint = zoneToEndpoint; } - public URI apply(Object from) { + @Override + public URI apply(@Nullable Object from) { + checkArgument(from != null, "you must specify a zone"); return zoneToEndpoint.get(from); } - } \ No newline at end of file diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java index 2acde48a95..a480b10105 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java @@ -102,17 +102,21 @@ public class AWSEC2ComputeService extends EC2ComputeService { void deletePlacementGroup(String region, String tag) { Preconditions2.checkNotEmpty(tag, "tag"); String group = String.format("jclouds#%s#%s", tag, region); - if (ec2Client.getPlacementGroupServices().describePlacementGroupsInRegion(region, group).size() > 0) { - logger.debug(">> deleting placementGroup(%s)", group); - try { - ec2Client.getPlacementGroupServices().deletePlacementGroupInRegion(region, group); - checkState(placementGroupDeleted.apply(new PlacementGroup(region, group, "cluster", State.PENDING)), String - .format("placementGroup region(%s) name(%s) failed to delete", region, group)); - placementGroupMap.remove(new RegionAndName(region, group)); - logger.debug("<< deleted placementGroup(%s)", group); - } catch (IllegalStateException e) { - logger.debug("<< inUse placementGroup(%s)", group); + try { + if (ec2Client.getPlacementGroupServices().describePlacementGroupsInRegion(region, group).size() > 0) { + logger.debug(">> deleting placementGroup(%s)", group); + try { + ec2Client.getPlacementGroupServices().deletePlacementGroupInRegion(region, group); + checkState(placementGroupDeleted.apply(new PlacementGroup(region, group, "cluster", State.PENDING)), + String.format("placementGroup region(%s) name(%s) failed to delete", region, group)); + placementGroupMap.remove(new RegionAndName(region, group)); + logger.debug("<< deleted placementGroup(%s)", group); + } catch (IllegalStateException e) { + logger.debug("<< inUse placementGroup(%s)", group); + } } + } catch (UnsupportedOperationException e) { + logger.trace("<< placementGroups unsupported in region %s", region); } } 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 a3688d7f2d..51cb7ae5f6 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 @@ -23,10 +23,14 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import java.util.Arrays; +import java.util.Set; + +import javax.annotation.Nullable; import org.jclouds.compute.options.TemplateOptions; import org.jclouds.domain.Credentials; import org.jclouds.ec2.compute.options.EC2TemplateOptions; +import org.jclouds.ec2.domain.BlockDeviceMapping; import org.jclouds.io.Payload; import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.util.Preconditions2; @@ -98,13 +102,54 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions { } public static class Builder { + /** + * @see EC2TemplateOptions#blockDeviceMappings + */ + public static AWSEC2TemplateOptions blockDeviceMappings(Set blockDeviceMappings) { + AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); + return options.blockDeviceMappings(blockDeviceMappings); + } + + /** + * @see EC2TemplateOptions#mapEBSSnapshotToDeviceName + */ + public static AWSEC2TemplateOptions mapEBSSnapshotToDeviceName(String deviceName, String snapshotId, + @Nullable Integer sizeInGib, boolean deleteOnTermination) { + AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); + return options.mapEBSSnapshotToDeviceName(deviceName, snapshotId, sizeInGib, deleteOnTermination); + } + + /** + * @see EC2TemplateOptions#mapNewVolumeToDeviceName + */ + public static AWSEC2TemplateOptions mapNewVolumeToDeviceName(String deviceName, int sizeInGib, + boolean deleteOnTermination) { + AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); + return options.mapNewVolumeToDeviceName(deviceName, sizeInGib, deleteOnTermination); + } + + /** + * @see EC2TemplateOptions#mapEphemeralDeviceToDeviceName + */ + public static AWSEC2TemplateOptions mapEphemeralDeviceToDeviceName(String deviceName, String virtualName) { + AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); + return options.mapEphemeralDeviceToDeviceName(deviceName, virtualName); + } + + /** + * @see EC2TemplateOptions#unmapDeviceNamed + */ + public static AWSEC2TemplateOptions unmapDeviceNamed(String deviceName) { + AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); + return options.unmapDeviceNamed(deviceName); + } /** * @see AWSEC2TemplateOptions#securityGroups(Iterable) */ public static AWSEC2TemplateOptions securityGroups(String... groupIds) { AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); - return AWSEC2TemplateOptions.class.cast(options.securityGroups(groupIds)); + return options.securityGroups(groupIds); } /** @@ -112,7 +157,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions { */ public static AWSEC2TemplateOptions securityGroups(Iterable groupIds) { AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); - return AWSEC2TemplateOptions.class.cast(options.securityGroups(groupIds)); + return options.securityGroups(groupIds); } /** @@ -120,7 +165,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions { */ public static AWSEC2TemplateOptions keyPair(String keyPair) { AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); - return AWSEC2TemplateOptions.class.cast(options.keyPair(keyPair)); + return options.keyPair(keyPair); } /** @@ -128,7 +173,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions { */ public static AWSEC2TemplateOptions userData(byte[] unencodedData) { AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); - return AWSEC2TemplateOptions.class.cast(options.userData(unencodedData)); + return options.userData(unencodedData); } /** @@ -136,7 +181,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions { */ public static AWSEC2TemplateOptions noKeyPair() { AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); - return AWSEC2TemplateOptions.class.cast(options.noKeyPair()); + return options.noKeyPair(); } /** @@ -144,7 +189,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions { */ public static AWSEC2TemplateOptions placementGroup(String placementGroup) { AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); - return AWSEC2TemplateOptions.class.cast(options.placementGroup(placementGroup)); + return options.placementGroup(placementGroup); } /** @@ -152,7 +197,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions { */ public static AWSEC2TemplateOptions noPlacementGroup() { AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); - return AWSEC2TemplateOptions.class.cast(options.noPlacementGroup()); + return options.noPlacementGroup(); } /** @@ -160,7 +205,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions { */ public static AWSEC2TemplateOptions enableMonitoring() { AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); - return AWSEC2TemplateOptions.class.cast(options.enableMonitoring()); + return options.enableMonitoring(); } // methods that only facilitate returning the correct object type @@ -169,7 +214,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions { */ public static AWSEC2TemplateOptions inboundPorts(int... ports) { AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); - return AWSEC2TemplateOptions.class.cast(options.inboundPorts(ports)); + return options.inboundPorts(ports); } /** @@ -177,7 +222,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions { */ public static AWSEC2TemplateOptions blockOnPort(int port, int seconds) { AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); - return AWSEC2TemplateOptions.class.cast(options.blockOnPort(port, seconds)); + return options.blockOnPort(port, seconds); } /** @@ -185,7 +230,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions { */ public static AWSEC2TemplateOptions runScript(byte[] script) { AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); - return AWSEC2TemplateOptions.class.cast(options.runScript(script)); + return options.runScript(script); } /** @@ -193,7 +238,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions { */ public static AWSEC2TemplateOptions installPrivateKey(String rsaKey) { AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); - return AWSEC2TemplateOptions.class.cast(options.installPrivateKey(rsaKey)); + return options.installPrivateKey(rsaKey); } /** @@ -201,7 +246,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions { */ public static AWSEC2TemplateOptions authorizePublicKey(String rsaKey) { AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); - return AWSEC2TemplateOptions.class.cast(options.authorizePublicKey(rsaKey)); + return options.authorizePublicKey(rsaKey); } /** @@ -209,7 +254,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions { */ public static AWSEC2TemplateOptions withDetails() { AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); - return AWSEC2TemplateOptions.class.cast(options.withMetadata()); + return options.withMetadata(); } /** @@ -217,12 +262,96 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions { */ public static AWSEC2TemplateOptions subnetId(String subnetId) { AWSEC2TemplateOptions options = new AWSEC2TemplateOptions(); - return AWSEC2TemplateOptions.class.cast(options.subnetId(subnetId)); + return options.subnetId(subnetId); } } // methods that only facilitate returning the correct object type + /** + * {@inheritDoc} + */ + @Override + public AWSEC2TemplateOptions blockDeviceMappings(Set blockDeviceMappings) { + return AWSEC2TemplateOptions.class.cast(super.blockDeviceMappings(blockDeviceMappings)); + } + + /** + * {@inheritDoc} + */ + @Override + public AWSEC2TemplateOptions keyPair(String keyPair) { + return AWSEC2TemplateOptions.class.cast(super.keyPair(keyPair)); + } + + /** + * {@inheritDoc} + */ + + @Override + public AWSEC2TemplateOptions mapEBSSnapshotToDeviceName(String deviceName, String snapshotId, Integer sizeInGib, + boolean deleteOnTermination) { + return AWSEC2TemplateOptions.class.cast(super.mapEBSSnapshotToDeviceName(deviceName, snapshotId, sizeInGib, + deleteOnTermination)); + } + + /** + * {@inheritDoc} + */ + @Override + public AWSEC2TemplateOptions mapEphemeralDeviceToDeviceName(String deviceName, String virtualName) { + return AWSEC2TemplateOptions.class.cast(super.mapEphemeralDeviceToDeviceName(deviceName, virtualName)); + } + + /** + * {@inheritDoc} + */ + @Override + public AWSEC2TemplateOptions mapNewVolumeToDeviceName(String deviceName, int sizeInGib, boolean deleteOnTermination) { + return AWSEC2TemplateOptions.class.cast(super + .mapNewVolumeToDeviceName(deviceName, sizeInGib, deleteOnTermination)); + } + + /** + * {@inheritDoc} + */ + @Override + public AWSEC2TemplateOptions noKeyPair() { + return AWSEC2TemplateOptions.class.cast(super.noKeyPair()); + } + + /** + * {@inheritDoc} + */ + @Override + public AWSEC2TemplateOptions securityGroups(Iterable groupIds) { + return AWSEC2TemplateOptions.class.cast(super.securityGroups(groupIds)); + } + + /** + * {@inheritDoc} + */ + @Override + public AWSEC2TemplateOptions securityGroups(String... groupIds) { + return AWSEC2TemplateOptions.class.cast(super.securityGroups(groupIds)); + } + + /** + * {@inheritDoc} + */ + @Override + public AWSEC2TemplateOptions unmapDeviceNamed(String deviceName) { + return AWSEC2TemplateOptions.class.cast(super.unmapDeviceNamed(deviceName)); + } + + /** + * {@inheritDoc} + */ + @Override + public AWSEC2TemplateOptions userData(byte[] unencodedData) { + return AWSEC2TemplateOptions.class.cast(super.userData(unencodedData)); + } + /** * {@inheritDoc} */ @@ -414,7 +543,7 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions { @Override public String toString() { - return "AWSEC2TemplateOptions [groupIds=" + getGroupIds() + ", keyPair=" + getKeyPair() + ", noKeyPair=" + return "[groupIds=" + getGroupIds() + ", keyPair=" + getKeyPair() + ", noKeyPair=" + !shouldAutomaticallyCreateKeyPair() + ", monitoringEnabled=" + monitoringEnabled + ", placementGroup=" + placementGroup + ", noPlacementGroup=" + noPlacementGroup + ", subnetId=" + subnetId + ", userData=" + Arrays.toString(getUserData()) + ", blockDeviceMappings=" + getBlockDeviceMappings() + "]"; diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/config/AWSEC2ComputeServiceContextModule.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/config/AWSEC2ComputeServiceContextModule.java index 6d189a42c5..0ea1bd580c 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/config/AWSEC2ComputeServiceContextModule.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/config/AWSEC2ComputeServiceContextModule.java @@ -22,7 +22,6 @@ package org.jclouds.aws.ec2.compute.config; import static org.jclouds.compute.domain.OsFamily.AMZN_LINUX; import org.jclouds.aws.ec2.compute.AWSEC2TemplateBuilderImpl; -import org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions; import org.jclouds.aws.ec2.compute.strategy.AWSEC2ReviseParsedImage; import org.jclouds.aws.ec2.compute.strategy.CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions; import org.jclouds.aws.ec2.compute.suppliers.AWSEC2HardwareSupplier; @@ -30,7 +29,6 @@ import org.jclouds.aws.ec2.compute.suppliers.AWSRegionAndNameToImageSupplier; import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.ec2.compute.config.EC2ComputeServiceContextModule; import org.jclouds.ec2.compute.internal.EC2TemplateBuilderImpl; -import org.jclouds.ec2.compute.options.EC2TemplateOptions; import org.jclouds.ec2.compute.strategy.CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions; import org.jclouds.ec2.compute.strategy.ReviseParsedImage; import org.jclouds.ec2.compute.suppliers.EC2HardwareSupplier; @@ -58,7 +56,6 @@ public class AWSEC2ComputeServiceContextModule extends EC2ComputeServiceContextM bind(EC2HardwareSupplier.class).to(AWSEC2HardwareSupplier.class); bind(RegionAndNameToImageSupplier.class).to(AWSRegionAndNameToImageSupplier.class); bind(EC2TemplateBuilderImpl.class).to(AWSEC2TemplateBuilderImpl.class); - bind(EC2TemplateOptions.class).to(AWSEC2TemplateOptions.class); } @Override diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/config/AWSEC2ComputeServiceDependenciesModule.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/config/AWSEC2ComputeServiceDependenciesModule.java index b8f0b723c3..cfdfd72bc2 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/config/AWSEC2ComputeServiceDependenciesModule.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/config/AWSEC2ComputeServiceDependenciesModule.java @@ -32,6 +32,7 @@ import javax.inject.Singleton; import org.jclouds.aws.ec2.AWSEC2AsyncClient; import org.jclouds.aws.ec2.AWSEC2Client; import org.jclouds.aws.ec2.compute.AWSEC2ComputeService; +import org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions; import org.jclouds.aws.ec2.domain.PlacementGroup; import org.jclouds.aws.ec2.predicates.PlacementGroupAvailable; import org.jclouds.aws.ec2.predicates.PlacementGroupDeleted; @@ -48,7 +49,6 @@ import org.jclouds.ec2.compute.functions.CreateSecurityGroupIfNeeded; import org.jclouds.ec2.compute.functions.CredentialsForInstance; import org.jclouds.ec2.compute.functions.RunningInstanceToNodeMetadata; import org.jclouds.ec2.compute.internal.EC2TemplateBuilderImpl; -import org.jclouds.ec2.compute.options.EC2TemplateOptions; import org.jclouds.ec2.domain.RunningInstance; import org.jclouds.predicates.RetryablePredicate; import org.jclouds.rest.RestContext; @@ -69,7 +69,7 @@ public class AWSEC2ComputeServiceDependenciesModule extends EC2ComputeServiceDep @Override protected void configure() { bind(TemplateBuilder.class).to(EC2TemplateBuilderImpl.class); - bind(TemplateOptions.class).to(EC2TemplateOptions.class); + bind(TemplateOptions.class).to(AWSEC2TemplateOptions.class); bind(ComputeService.class).to(AWSEC2ComputeService.class); bind(new TypeLiteral>() { }).to(RunningInstanceToNodeMetadata.class); diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/options/AWSRunInstancesOptionsTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/options/AWSRunInstancesOptionsTest.java index daf8e3928d..ff28c73d25 100644 --- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/options/AWSRunInstancesOptionsTest.java +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/options/AWSRunInstancesOptionsTest.java @@ -31,14 +31,14 @@ import static org.jclouds.aws.ec2.options.AWSRunInstancesOptions.Builder.withUse import static org.testng.Assert.assertEquals; import java.util.Collections; -import java.util.HashSet; -import java.util.Set; import org.jclouds.ec2.domain.BlockDeviceMapping; import org.jclouds.ec2.domain.InstanceType; import org.jclouds.http.options.HttpRequestOptions; import org.testng.annotations.Test; +import com.google.common.collect.ImmutableSet; + /** * Tests possible uses of AWSRunInstancesOptions and AWSRunInstancesOptions.Builder.* * @@ -255,17 +255,18 @@ public class AWSRunInstancesOptionsTest { AWSRunInstancesOptions options = new AWSRunInstancesOptions(); assertEquals(options.buildFormParameters().get("BlockDeviceMapping.VirtualName"), Collections.EMPTY_LIST); } - + @Test public void testWithBlockDeviceMapping() { - AWSRunInstancesOptions options = new AWSRunInstancesOptions(); - BlockDeviceMapping mapping = new BlockDeviceMapping("/dev/sda1", null, null, 120, null, true); - Set mappings = new HashSet(); - mappings.add(mapping); - options.withBlockDeviceMappings(mappings); - assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.DeviceName"), Collections.singletonList("/dev/sda1")); - assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.VolumeSize"), Collections.singletonList("120")); - assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.DeleteOnTermination"), Collections.singletonList("true")); + BlockDeviceMapping mapping = new BlockDeviceMapping.MapNewVolumeToDevice("/dev/sda1", 120, true); + AWSRunInstancesOptions options = new AWSRunInstancesOptions().withBlockDeviceMappings(ImmutableSet + . of(mapping)); + assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.DeviceName"), Collections + .singletonList("/dev/sda1")); + assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.VolumeSize"), Collections + .singletonList("120")); + assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.DeleteOnTermination"), Collections + .singletonList("true")); } @Test @@ -276,18 +277,19 @@ public class AWSRunInstancesOptionsTest { @Test public void testWithBlockDeviceMappingStatic() { - BlockDeviceMapping mapping = new BlockDeviceMapping("/dev/sda1", null, null, 120, null, true); - Set mappings = new HashSet(); - mappings.add(mapping); - AWSRunInstancesOptions options = withBlockDeviceMappings(mappings); - assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.DeviceName"), Collections.singletonList("/dev/sda1")); - assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.VolumeSize"), Collections.singletonList("120")); - assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.DeleteOnTermination"), Collections.singletonList("true")); + BlockDeviceMapping mapping = new BlockDeviceMapping.MapNewVolumeToDevice("/dev/sda1", 120, true); + AWSRunInstancesOptions options = withBlockDeviceMappings(ImmutableSet. of(mapping)); + assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.DeviceName"), Collections + .singletonList("/dev/sda1")); + assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.VolumeSize"), Collections + .singletonList("120")); + assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.DeleteOnTermination"), Collections + .singletonList("true")); } @Test(expectedExceptions = NullPointerException.class) public void testWithBlockDeviceMappingNPE() { - withBlockDeviceMappings(null); + withBlockDeviceMappings(null); } }