JCLOUDS-602 - Add support for volumeType, iops and encrypted to EBS.

Adds CreateVolumeOptions for volume creation, adds support for the
above EBS configs in Image, Volume, BlockDeviceMapping, etc.
This commit is contained in:
Andrew Bayer 2014-06-19 11:24:29 -07:00
parent da50cd6cbe
commit 6451098f72
27 changed files with 942 additions and 121 deletions

View File

@ -187,12 +187,27 @@ public class EC2TemplateOptions extends TemplateOptions implements Cloneable {
public EC2TemplateOptions mapEBSSnapshotToDeviceName(String deviceName, String snapshotId,
@Nullable Integer sizeInGib, boolean deleteOnTermination) {
blockDeviceMappings.add(new MapEBSSnapshotToDevice(deviceName, snapshotId, sizeInGib, deleteOnTermination));
return mapEBSSnapshotToDeviceName(deviceName, snapshotId, sizeInGib, deleteOnTermination, null, null, false);
}
public EC2TemplateOptions mapEBSSnapshotToDeviceName(String deviceName, String snapshotId,
@Nullable Integer sizeInGib, boolean deleteOnTermination,
@Nullable String volumeType, @Nullable Integer iops,
boolean encrypted) {
blockDeviceMappings.add(new MapEBSSnapshotToDevice(deviceName, snapshotId, sizeInGib, deleteOnTermination,
volumeType, iops, encrypted));
return this;
}
public EC2TemplateOptions mapNewVolumeToDeviceName(String deviceName, int sizeInGib, boolean deleteOnTermination) {
blockDeviceMappings.add(new MapNewVolumeToDevice(deviceName, sizeInGib, deleteOnTermination));
return mapNewVolumeToDeviceName(deviceName, sizeInGib, deleteOnTermination, null, null, false);
}
public EC2TemplateOptions mapNewVolumeToDeviceName(String deviceName, int sizeInGib, boolean deleteOnTermination,
@Nullable String volumeType, @Nullable Integer iops,
boolean encrypted) {
blockDeviceMappings.add(new MapNewVolumeToDevice(deviceName, sizeInGib, deleteOnTermination, volumeType,
iops, encrypted));
return this;
}

View File

@ -34,6 +34,9 @@ public class BlockDeviceMapping implements Comparable<BlockDeviceMapping> {
private Integer sizeInGib;
private Boolean noDevice;
private Boolean deleteOnTermination;
private String volumeType;
private Integer iops;
private Boolean encrypted;
public Builder deviceName(String deviceName) {
this.deviceName = deviceName;
@ -65,8 +68,24 @@ public class BlockDeviceMapping implements Comparable<BlockDeviceMapping> {
return this;
}
public Builder volumeType(String volumeType) {
this.volumeType = volumeType;
return this;
}
public Builder iops(Integer iops) {
this.iops = iops;
return this;
}
public Builder encrypted(Boolean encrypted) {
this.encrypted = encrypted;
return this;
}
public BlockDeviceMapping build() {
return new BlockDeviceMapping(deviceName, virtualName, snapshotId, sizeInGib, noDevice, deleteOnTermination);
return new BlockDeviceMapping(deviceName, virtualName, snapshotId, sizeInGib, noDevice, deleteOnTermination,
volumeType, iops, encrypted);
}
public Builder clear() {
@ -76,6 +95,9 @@ public class BlockDeviceMapping implements Comparable<BlockDeviceMapping> {
this.sizeInGib = null;
this.noDevice = null;
this.deleteOnTermination = null;
this.volumeType = null;
this.iops = null;
this.encrypted = null;
return this;
}
}
@ -86,13 +108,17 @@ public class BlockDeviceMapping implements Comparable<BlockDeviceMapping> {
private final Integer sizeInGib;
private final Boolean noDevice;
private final Boolean deleteOnTermination;
private final String volumeType;
private final Integer iops;
private final Boolean encrypted;
// values expressed in GB
private static final Integer VOLUME_SIZE_MIN_VALUE = 1;
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,
@Nullable String volumeType, @Nullable Integer iops, @Nullable Boolean encrypted) {
checkNotNull(deviceName, "deviceName cannot be null");
checkNotNull(emptyToNull(deviceName), "deviceName must be defined");
@ -107,6 +133,9 @@ public class BlockDeviceMapping implements Comparable<BlockDeviceMapping> {
this.sizeInGib = sizeInGib;
this.noDevice = noDevice;
this.deleteOnTermination = deleteOnTermination;
this.volumeType = volumeType;
this.iops = iops;
this.encrypted = encrypted;
}
public String getDeviceName() {
@ -133,6 +162,18 @@ public class BlockDeviceMapping implements Comparable<BlockDeviceMapping> {
return deleteOnTermination;
}
public String getEbsVolumeType() {
return volumeType;
}
public Integer getEbsIops() {
return iops;
}
public Boolean getEbsEncrypted() {
return encrypted;
}
@Override
public int hashCode() {
final int prime = 31;
@ -143,6 +184,9 @@ public class BlockDeviceMapping implements Comparable<BlockDeviceMapping> {
result = prime * result + ((sizeInGib == null) ? 0 : sizeInGib.hashCode());
result = prime * result + ((snapshotId == null) ? 0 : snapshotId.hashCode());
result = prime * result + ((virtualName == null) ? 0 : virtualName.hashCode());
result = prime * result + ((volumeType == null) ? 0 : volumeType.hashCode());
result = prime * result + ((iops == null) ? 0 : iops.hashCode());
result = prime * result + ((encrypted == null ) ? 0 : encrypted.hashCode());
return result;
}
@ -185,41 +229,59 @@ public class BlockDeviceMapping implements Comparable<BlockDeviceMapping> {
return false;
} else if (!virtualName.equals(other.virtualName))
return false;
if (volumeType == null) {
if (other.volumeType != null)
return false;
} else if (!volumeType.equals(other.volumeType))
return false;
if (iops== null) {
if (other.iops != null)
return false;
} else if (!iops.equals(other.iops))
return false;
if (encrypted == null) {
if (other.encrypted != null)
return false;
} else if (!encrypted.equals(other.encrypted))
return false;
return true;
}
@Override
public String toString() {
return "[deviceName=" + deviceName + ", virtualName=" + virtualName + ", snapshotId=" + snapshotId
+ ", sizeInGib=" + sizeInGib + ", noDevice=" + noDevice + ", deleteOnTermination=" + deleteOnTermination
+ "]";
+ ", sizeInGib=" + sizeInGib + ", noDevice=" + noDevice + ", deleteOnTermination=" + deleteOnTermination
+ ", volumeType=" + volumeType + ", iops=" + iops + ", encrypted=" + encrypted
+ "]";
}
public static class MapEBSSnapshotToDevice extends BlockDeviceMapping {
public MapEBSSnapshotToDevice(String deviceName, String snapshotId, @Nullable Integer sizeInGib,
@Nullable Boolean deleteOnTermination) {
super(deviceName, null, snapshotId, sizeInGib, null, deleteOnTermination);
@Nullable Boolean deleteOnTermination, @Nullable String volumeType,
@Nullable Integer iops, @Nullable Boolean encrypted) {
super(deviceName, null, snapshotId, sizeInGib, null, deleteOnTermination, volumeType, iops, encrypted);
checkNotNull(emptyToNull(snapshotId), "snapshotId must be defined");
}
}
public static class MapNewVolumeToDevice extends BlockDeviceMapping {
public MapNewVolumeToDevice(String deviceName, Integer sizeInGib, @Nullable Boolean deleteOnTermination) {
super(deviceName, null, null, sizeInGib, null, deleteOnTermination);
public MapNewVolumeToDevice(String deviceName, Integer sizeInGib, @Nullable Boolean deleteOnTermination,
@Nullable String volumeType, @Nullable Integer iops, @Nullable Boolean encrypted) {
super(deviceName, null, null, sizeInGib, null, deleteOnTermination, volumeType, iops, encrypted);
checkNotNull(sizeInGib, "sizeInGib cannot be null");
}
}
public static class MapEphemeralDeviceToDevice extends BlockDeviceMapping {
public MapEphemeralDeviceToDevice(String deviceName, String virtualName) {
super(deviceName, virtualName, null, null, null, null);
super(deviceName, virtualName, null, null, null, null, null, null, null);
checkNotNull(emptyToNull(virtualName), "virtualName must be defined");
}
}
public static class UnmapDeviceNamed extends BlockDeviceMapping {
public UnmapDeviceNamed(String deviceName) {
super(deviceName, null, null, null, true, null);
super(deviceName, null, null, null, true, null, null, null, null);
}
}

View File

@ -159,11 +159,18 @@ public class Image implements Comparable<Image> {
private final String snapshotId;
private final long volumeSize;
private final boolean deleteOnTermination;
private final String volumeType;
private final Integer iops;
private final boolean encrypted;
public EbsBlockDevice(@Nullable String snapshotId, long volumeSize, boolean deleteOnTermination) {
public EbsBlockDevice(@Nullable String snapshotId, long volumeSize, boolean deleteOnTermination,
@Nullable String volumeType, @Nullable Integer iops, boolean encrypted) {
this.snapshotId = snapshotId;
this.volumeSize = volumeSize;
this.deleteOnTermination = deleteOnTermination;
this.volumeType = volumeType;
this.iops = iops;
this.encrypted = encrypted;
}
public String getSnapshotId() {
@ -178,6 +185,18 @@ public class Image implements Comparable<Image> {
return deleteOnTermination;
}
public String getVolumeType() {
return volumeType;
}
public Integer getIops() {
return iops;
}
public boolean isEncrypted() {
return encrypted;
}
@Override
public int hashCode() {
final int prime = 31;
@ -185,6 +204,9 @@ public class Image implements Comparable<Image> {
result = prime * result + (deleteOnTermination ? 1231 : 1237);
result = prime * result + ((snapshotId == null) ? 0 : snapshotId.hashCode());
result = prime * result + (int) (volumeSize ^ (volumeSize >>> 32));
result = prime * result + (encrypted ? 1249 : 1259);
result = prime * result + ((volumeType == null) ? 0 : volumeType.hashCode());
result = prime * result + ((iops == null) ? 0 : iops.hashCode());
return result;
}
@ -199,11 +221,23 @@ public class Image implements Comparable<Image> {
EbsBlockDevice other = (EbsBlockDevice) obj;
if (deleteOnTermination != other.deleteOnTermination)
return false;
if (encrypted != other.encrypted)
return false;
if (snapshotId == null) {
if (other.snapshotId != null)
return false;
} else if (!snapshotId.equals(other.snapshotId))
return false;
if (volumeType == null) {
if (other.volumeType != null)
return false;
} else if (!volumeType.equals(other.volumeType))
return false;
if (iops == null) {
if (other.iops != null)
return false;
} else if (!iops.equals(other.iops))
return false;
if (volumeSize != other.volumeSize)
return false;
return true;
@ -212,7 +246,8 @@ public class Image implements Comparable<Image> {
@Override
public String toString() {
return "EbsBlockDevice [deleteOnTermination=" + deleteOnTermination + ", snapshotId=" + snapshotId
+ ", volumeSize=" + volumeSize + "]";
+ ", volumeSize=" + volumeSize + ", volumeType=" + volumeType + ", iops=" + iops
+ ", encrypted=" + encrypted + "]";
}
}

View File

@ -98,6 +98,11 @@ public class Volume implements Comparable<Volume> {
private Status status;
private Date createTime;
private Set<Attachment> attachments = ImmutableSet.of();
@Nullable
private String volumeType;
@Nullable
private Integer iops;
private boolean encrypted = false;
public Builder region(String region) {
this.region = region;
@ -143,15 +148,31 @@ public class Volume implements Comparable<Volume> {
this.attachments = ImmutableSet.copyOf(attachments);
return this;
}
public Builder volumeType(String volumeType) {
this.volumeType = volumeType;
return this;
}
public Builder iops(Integer iops) {
this.iops = iops;
return this;
}
public Builder encrypted(boolean encrypted) {
this.encrypted = encrypted;
return this;
}
public Volume build() {
return new Volume(region, id, size, snapshotId, availabilityZone, status, createTime, attachments);
return new Volume(region, id, size, snapshotId, availabilityZone, status, createTime,
volumeType, iops, encrypted, attachments);
}
public Builder fromVolume(Volume in) {
return region(in.region).id(in.id).size(in.size).snapshotId(in.snapshotId)
.availabilityZone(in.availabilityZone).status(in.status).createTime(in.createTime)
.attachments(in.attachments);
.volumeType(in.volumeType).iops(in.iops).encrypted(in.encrypted).attachments(in.attachments);
}
}
@ -165,8 +186,14 @@ public class Volume implements Comparable<Volume> {
private final Date createTime;
private final Set<Attachment> attachments;
@Nullable
private final String volumeType;
@Nullable
private final Integer iops;
private final boolean encrypted;
public Volume(String region, String id, int size, String snapshotId, String availabilityZone, Volume.Status status,
Date createTime, Iterable<Attachment> attachments) {
Date createTime, String volumeType, Integer iops, boolean encrypted, Iterable<Attachment> attachments) {
this.region = checkNotNull(region, "region");
this.id = id;
this.size = size;
@ -174,6 +201,9 @@ public class Volume implements Comparable<Volume> {
this.availabilityZone = availabilityZone;
this.status = status;
this.createTime = createTime;
this.volumeType = volumeType;
this.iops = iops;
this.encrypted = encrypted;
this.attachments = ImmutableSet.copyOf(attachments);
}
@ -212,6 +242,18 @@ public class Volume implements Comparable<Volume> {
return createTime;
}
public String getVolumeType() {
return volumeType;
}
public Integer getIops() {
return iops;
}
public boolean getEncrypted() {
return encrypted;
}
public Set<Attachment> getAttachments() {
return attachments;
}
@ -228,7 +270,10 @@ public class Volume implements Comparable<Volume> {
result = prime * result + size;
result = prime * result + ((snapshotId == null) ? 0 : snapshotId.hashCode());
result = prime * result + ((status == null) ? 0 : status.hashCode());
return result;
result = prime * result + ((volumeType == null) ? 0 : volumeType.hashCode());
result = prime * result + ((iops == null) ? 0 : iops.hashCode());
result = prime * result + (encrypted ? 1249 : 1259);
return result;
}
@Override
@ -277,6 +322,18 @@ public class Volume implements Comparable<Volume> {
return false;
} else if (!status.equals(other.status))
return false;
if (volumeType == null) {
if (other.volumeType != null)
return false;
} else if (!volumeType.equals(other.volumeType))
return false;
if (iops == null) {
if (other.iops != null)
return false;
} else if (!iops.equals(other.iops))
return false;
if (encrypted != other.encrypted)
return false;
return true;
}
@ -288,7 +345,8 @@ public class Volume implements Comparable<Volume> {
@Override
public String toString() {
return "Volume [attachments=" + attachments + ", availabilityZone=" + availabilityZone + ", createTime="
+ createTime + ", id=" + id + ", region=" + region + ", size=" + size + ", snapshotId=" + snapshotId
+ ", status=" + status + "]";
+ createTime + ", id=" + id + ", region=" + region + ", size=" + size + ", snapshotId=" + snapshotId
+ ", status=" + status + ", volumeType=" + volumeType + ", iops=" + iops + ", encrypted=" + encrypted
+"]";
}
}

View File

@ -37,6 +37,7 @@ import org.jclouds.ec2.domain.Permission;
import org.jclouds.ec2.domain.Snapshot;
import org.jclouds.ec2.domain.Volume;
import org.jclouds.ec2.options.CreateSnapshotOptions;
import org.jclouds.ec2.options.CreateVolumeOptions;
import org.jclouds.ec2.options.DescribeSnapshotsOptions;
import org.jclouds.ec2.options.DetachVolumeOptions;
import org.jclouds.ec2.xml.AttachmentHandler;
@ -164,6 +165,36 @@ public interface ElasticBlockStoreApi {
@EndpointParam(parser = ZoneToEndpoint.class) @FormParam("AvailabilityZone") String availabilityZone,
@FormParam("Size") int size);
/**
* Creates a new Amazon EBS volume to which any Amazon EC2 instance can attach within the same
* Availability Zone. For more information about Amazon EBS, go to the Amazon Elastic Compute
* Cloud Developer Guide or Amazon Elastic Compute Cloud User Guide.
*
* @param availabilityZone
* An Amazon EBS volume must be located within the same Availability Zone as the
* instance to which it attaches.
* @param options
* options like specifying a snapshot, EBS volume type, etc
*
*
* @see #describeVolumesInRegion
* @see #deleteVolumeInRegion
* @see #attachVolumeInRegion
* @see #detachVolumeInRegion
* @see AvailabilityZoneAndRegionApi#describeAvailabilityZonesInRegion
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-CreateVolume.html"
* />
*/
@Named("CreateVolume")
@POST
@Path("/")
@FormParams(keys = ACTION, values = "CreateVolume")
@XMLResponseParser(CreateVolumeResponseHandler.class)
Volume createVolumeInAvailabilityZone(
@EndpointParam(parser = ZoneToEndpoint.class) @FormParam("AvailabilityZone") String availabilityZone,
CreateVolumeOptions... options);
/**
* Describes the specified Amazon EBS volumes that you own. If you do not specify one or more
* volume IDs, Amazon EBS describes all volumes that you own. For more information about Amazon

View File

@ -0,0 +1,146 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.ec2.options;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.ec2.options.internal.BaseEC2RequestOptions;
/**
* Contains options supported in the Form API for the CreateVolume operation. <h2>
* Usage</h2> The recommended way to instantiate a CreateVolumeOptions object is to statically
* import CreateVolumeOptions.Builder.* and invoke a static creation method followed by an
* instance mutator (if needed):
* <p/>
* <code>
* import static org.jclouds.ec2.options.CreateVolumeOptions.Builder.*
* <p/>
* EC2Api connection = // get connection
* Volume volume = connection.getElasticBlockStoreApi().get().createVolumeInAvailabilityZone(availabilityZone, fromSnapshotId("123125"));
* <code>
*
* @see <a
* href="http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-CreateVolume.html"
* />
*/
public class CreateVolumeOptions extends BaseEC2RequestOptions {
/**
* Snapshot ID to create this volume from.
*/
public CreateVolumeOptions withSize(int size) {
formParameters.put("Size", Integer.toString(size));
return this;
}
public int getSize() {
return Integer.parseInt(getFirstFormOrNull("Size"));
}
/**
* Snapshot ID to create this volume from.
*/
public CreateVolumeOptions fromSnapshotId(String snapshotId) {
formParameters.put("SnapshotId", checkNotNull(snapshotId, "snapshotId"));
return this;
}
public String getSnapshotId() {
return getFirstFormOrNull("SnapshotId");
}
/**
* EBS volume type to use - if not specified, will be "standard".
*/
public CreateVolumeOptions volumeType(String volumeType) {
formParameters.put("VolumeType", checkNotNull(volumeType, "volumeType"));
return this;
}
public String getVolumeType() {
return getFirstFormOrNull("VolumeType");
}
/**
* EBS provisioned IOPS
*/
public CreateVolumeOptions withIops(Integer iops) {
formParameters.put("Iops", checkNotNull(iops, "iops").toString());
return this;
}
public Integer getIops() {
return Integer.valueOf(getFirstFormOrNull("Iops"));
}
/**
* Should this EBS volume be encrypted?
*/
public CreateVolumeOptions isEncrypted(boolean encrypted) {
if (encrypted)
formParameters.put("Encrypted", "true");
return this;
}
public boolean getEncrypted() {
return Boolean.parseBoolean(getFirstFormOrNull("Encrypted"));
}
public static class Builder {
/**
* @see CreateVolumeOptions#fromSnapshotId(String)
*/
public static CreateVolumeOptions fromSnapshotId(String snapshotId) {
CreateVolumeOptions options = new CreateVolumeOptions();
return options.fromSnapshotId(snapshotId);
}
/**
* @see CreateVolumeOptions#withSize(int)
*/
public static CreateVolumeOptions withSize(int size) {
CreateVolumeOptions options = new CreateVolumeOptions();
return options.withSize(size);
}
/**
* @see CreateVolumeOptions#volumeType(String)
*/
public static CreateVolumeOptions volumeType(String volumeType) {
CreateVolumeOptions options = new CreateVolumeOptions();
return options.volumeType(volumeType);
}
/**
* @see CreateVolumeOptions#withIops(Integer)
*/
public static CreateVolumeOptions withIops(Integer iops) {
CreateVolumeOptions options = new CreateVolumeOptions();
return options.withIops(iops);
}
/**
* @see CreateVolumeOptions#isEncrypted(boolean)
*/
public static CreateVolumeOptions isEncrypted(boolean encrypted) {
CreateVolumeOptions options = new CreateVolumeOptions();
return options.isEncrypted(encrypted);
}
}
}

View File

@ -94,9 +94,90 @@ public class RegisterImageBackedByEbsOptions extends RegisterImageOptions {
/**
*
* adds a block device to the image from an ebs snapshot.
*
* @param deviceName
* The device name (e.g., /dev/sdh).
* @param virtualName
* The virtual device name. (nullable)
* @param snapshotId
* The ID of the snapshot.
* @param deleteOnTermination
* Whether this volume should be automatically deleted on instance termination.
* Defaults to false.
* @param volumeType
* What EBS volume type should be used.
* @param iops
* EBS provisioned IOPS for this volume.
* @param encrypted
* Whether this volume should be encrypted.
*/
public RegisterImageBackedByEbsOptions addBlockDeviceFromSnapshot(String deviceName,
@Nullable String virtualName, String snapshotId, boolean deleteOnTermination,
@Nullable String volumeType, @Nullable Integer iops, boolean encrypted) {
addAdvancedEbsOptions(deleteOnTermination, volumeType, iops, encrypted);
addEphemeralBlockDeviceFromSnapshot(deviceName, virtualName, snapshotId);
return this;
}
/**
*
* adds a new block device to the image.
*
* @param deviceName
* The device name (e.g., /dev/sdh).
* @param virtualName
* The virtual device name. (nullable)
* @param volumeSize
* The size of the volume, in GiBs..
* @param deleteOnTermination
* Whether this volume should be automatically deleted on instance termination.
* Defaults to false.
* @param volumeType
* What EBS volume type should be used.
* @param iops
* EBS provisioned IOPS for this volume.
* @param encrypted
* Whether this volume should be encrypted.
*/
public RegisterImageBackedByEbsOptions addNewBlockDevice(String deviceName,
@Nullable String virtualName,
int volumeSize,
boolean deleteOnTermination,
@Nullable String volumeType,
@Nullable Integer iops,
boolean encrypted) {
addAdvancedEbsOptions(deleteOnTermination, volumeType, iops, encrypted);
addNewEphemeralBlockDevice(deviceName, virtualName, volumeSize);
return this;
}
private RegisterImageBackedByEbsOptions addAdvancedEbsOptions(boolean deleteOnTermination,
@Nullable String volumeType,
@Nullable Integer iops,
boolean encrypted) {
formParameters.put("BlockDeviceMapping." + deviceIndex + ".Ebs.DeleteOnTermination",
Boolean.toString(deleteOnTermination));
if (volumeType != null)
formParameters.put("BlockDeviceMapping." + deviceIndex + ".Ebs.VolumeType", volumeType);
if (iops != null)
formParameters.put("BlockDeviceMapping." + deviceIndex + ".Ebs.Iops", iops.toString());
if (encrypted)
formParameters.put("BlockDeviceMapping." + deviceIndex + ".Ebs.Encrypted", "true");
return this;
}
/**
*
* adds a block device to the image from an ebs snapshot. This device is retained on instance
* termination.
*
*
* @param name
* The device name (e.g., /dev/sdh).
* @param virtualName
@ -105,7 +186,7 @@ public class RegisterImageBackedByEbsOptions extends RegisterImageOptions {
* The ID of the snapshot.
*/
public RegisterImageBackedByEbsOptions addBlockDeviceFromSnapshot(String deviceName,
@Nullable String virtualName, String snapshotId) {
@Nullable String virtualName, String snapshotId) {
formParameters.put("BlockDeviceMapping." + deviceIndex + ".Ebs.DeleteOnTermination", "false");
addEphemeralBlockDeviceFromSnapshot(deviceName, virtualName, snapshotId);
return this;
@ -171,6 +252,21 @@ public class RegisterImageBackedByEbsOptions extends RegisterImageOptions {
return options.addBlockDeviceFromSnapshot(deviceName, virtualName, snapshotId);
}
/**
* @see RegisterImageBackedByEbsOptions#addBlockDeviceFromSnapshot(String, String, String, boolean, String, Integer, boolean)
*/
public static RegisterImageBackedByEbsOptions addBlockDeviceFromSnapshot(String deviceName,
@Nullable String virtualName,
String snapshotId,
boolean deleteOnTermination,
@Nullable String volumeType,
@Nullable Integer iops,
boolean encrypted) {
RegisterImageBackedByEbsOptions options = new RegisterImageBackedByEbsOptions();
return options.addBlockDeviceFromSnapshot(deviceName, virtualName, snapshotId, deleteOnTermination,
volumeType, iops, encrypted);
}
/**
* @see RegisterImageBackedByEbsOptions#addEphemeralBlockDeviceFromSnapshot(String, String,
* String)
@ -190,6 +286,21 @@ public class RegisterImageBackedByEbsOptions extends RegisterImageOptions {
return options.addNewBlockDevice(deviceName, virtualName, volumeSize);
}
/**
* @see RegisterImageBackedByEbsOptions#addNewBlockDevice(String, String, int, boolean, String, Integer, boolean)
*/
public static RegisterImageBackedByEbsOptions addNewBlockDevice(String deviceName,
@Nullable String virtualName,
int volumeSize,
boolean deleteOnTermination,
@Nullable String volumeType,
@Nullable Integer iops,
boolean encrypted) {
RegisterImageBackedByEbsOptions options = new RegisterImageBackedByEbsOptions();
return options.addNewBlockDevice(deviceName, virtualName, volumeSize, deleteOnTermination,
volumeType, iops, encrypted);
}
/**
* @see RegisterImageBackedByEbsOptions#addNewEphemeralBlockDevice(String, String, int)
*/

View File

@ -139,6 +139,13 @@ public class RunInstancesOptions extends BaseEC2RequestOptions {
if (mapping.getEbsDeleteOnTermination() != null)
formParameters.put(String.format("BlockDeviceMapping.%d.Ebs.DeleteOnTermination", i),
String.valueOf(mapping.getEbsDeleteOnTermination()));
if (mapping.getEbsVolumeType() != null)
formParameters.put(String.format("BlockDeviceMapping.%d.Ebs.VolumeType", i), mapping.getEbsVolumeType());
if (mapping.getEbsIops() != null)
formParameters.put(String.format("BlockDeviceMapping.%d.Ebs.Iops", i),
String.valueOf(mapping.getEbsIops()));
if (mapping.getEbsEncrypted() != null)
formParameters.put(String.format("BlockDeviceMapping.%d.Ebs.Encrypted", i), String.valueOf(mapping.getEbsEncrypted()));
i++;
}
return this;
@ -179,7 +186,7 @@ public class RunInstancesOptions extends BaseEC2RequestOptions {
}
/**
* @see RunInstancesOptions#asType(InstanceType)
* @see RunInstancesOptions#asType(String)
*/
public static RunInstancesOptions asType(String instanceType) {
RunInstancesOptions options = new RunInstancesOptions();

View File

@ -18,13 +18,16 @@ package org.jclouds.ec2.xml;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Inject;
import java.util.Date;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.inject.Inject;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.date.DateCodec;
import org.jclouds.date.DateCodecFactory;
@ -37,11 +40,6 @@ import org.jclouds.location.Zone;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.xml.sax.Attributes;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
public class CreateVolumeResponseHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Volume> {
protected final DateCodec dateCodec;
protected final Supplier<String> defaultRegion;
@ -73,6 +71,9 @@ public class CreateVolumeResponseHandler extends ParseSax.HandlerForGeneratedReq
protected String device;
protected Attachment.Status attachmentStatus;
protected Date attachTime;
protected String volumeType;
protected Integer iops;
protected boolean encrypted;
protected boolean inAttachmentSet;
@ -125,6 +126,14 @@ public class CreateVolumeResponseHandler extends ParseSax.HandlerForGeneratedReq
device = currentText.toString().trim();
} else if (qName.equals("attachTime")) {
attachTime = dateCodec.toDate(currentText.toString().trim());
} else if (qName.equals("volumeType")) {
volumeType = currentText.toString().trim();
if (volumeType.equals(""))
volumeType = null;
} else if (qName.equals("iops")) {
iops = Integer.parseInt(currentText.toString().trim());
} else if (qName.equals("encrypted")) {
encrypted = Boolean.parseBoolean(currentText.toString().trim());
} else if (qName.equals("item")) {
if (inAttachmentSet) {
attachments.add(new Attachment(region, volumeId, instanceId, device, attachmentStatus, attachTime));
@ -140,7 +149,8 @@ public class CreateVolumeResponseHandler extends ParseSax.HandlerForGeneratedReq
}
private Volume newVolume() {
Volume volume = new Volume(region, id, size, snapshotId, availabilityZone, volumeStatus, createTime, attachments);
Volume volume = new Volume(region, id, size, snapshotId, availabilityZone, volumeStatus, createTime,
volumeType, iops, encrypted, attachments);
id = null;
size = 0;
snapshotId = null;
@ -148,6 +158,9 @@ public class CreateVolumeResponseHandler extends ParseSax.HandlerForGeneratedReq
volumeStatus = null;
createTime = null;
attachments = Sets.newLinkedHashSet();
volumeType = null;
iops = null;
encrypted = false;
return volume;
}

View File

@ -19,29 +19,27 @@ package org.jclouds.ec2.xml;
import static org.jclouds.util.SaxUtils.currentOrNull;
import static org.jclouds.util.SaxUtils.equalsOrSuffix;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
import javax.inject.Inject;
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.ec2.domain.Hypervisor;
import org.jclouds.ec2.domain.Image;
import org.jclouds.ec2.domain.RootDeviceType;
import org.jclouds.ec2.domain.VirtualizationType;
import org.jclouds.ec2.domain.Image.Architecture;
import org.jclouds.ec2.domain.Image.EbsBlockDevice;
import org.jclouds.ec2.domain.Image.ImageState;
import org.jclouds.ec2.domain.Image.ImageType;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.location.Region;
import org.jclouds.logging.Logger;
import org.xml.sax.Attributes;
import java.util.Map;
import java.util.Set;
import com.google.common.base.Supplier;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.ec2.domain.Hypervisor;
import org.jclouds.ec2.domain.Image;
import org.jclouds.ec2.domain.Image.Architecture;
import org.jclouds.ec2.domain.Image.EbsBlockDevice;
import org.jclouds.ec2.domain.Image.ImageState;
import org.jclouds.ec2.domain.Image.ImageType;
import org.jclouds.ec2.domain.RootDeviceType;
import org.jclouds.ec2.domain.VirtualizationType;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.location.Region;
import org.jclouds.logging.Logger;
import org.xml.sax.Attributes;
/**
* Parses the following XML document:
@ -94,7 +92,9 @@ public class DescribeImagesResponseHandler extends ParseSax.HandlerForGeneratedR
private int volumeSize;
private boolean deleteOnTermination = true;// correct default is true.
private boolean encrypted = false;
private String volumeType;
private Integer iops;
private String rootDeviceName;
public Set<Image> getResult() {
@ -159,6 +159,12 @@ public class DescribeImagesResponseHandler extends ParseSax.HandlerForGeneratedR
volumeSize = Integer.parseInt(currentText.toString().trim());
} else if (qName.equals("deleteOnTermination")) {
deleteOnTermination = Boolean.parseBoolean(currentText.toString().trim());
} else if (qName.equals("encrypted")) {
encrypted = Boolean.parseBoolean(currentText.toString().trim());
} else if (qName.equals("iops")) {
iops = Integer.valueOf(currentText.toString().trim());
} else if (qName.equals("volumeType")) {
volumeType = currentText.toString().trim();
} else if (qName.equals("ramdiskId")) {
ramdiskId = currentText.toString().trim();
} else if (qName.equals("rootDeviceType")) {
@ -171,11 +177,15 @@ public class DescribeImagesResponseHandler extends ParseSax.HandlerForGeneratedR
hypervisor = Hypervisor.fromValue(currentText.toString().trim());
} else if (qName.equals("item")) {
if (inBlockDeviceMapping) {
ebsBlockDevices.put(deviceName, new Image.EbsBlockDevice(snapshotId, volumeSize, deleteOnTermination));
ebsBlockDevices.put(deviceName, new Image.EbsBlockDevice(snapshotId, volumeSize, deleteOnTermination,
volumeType, iops, encrypted));
this.deviceName = null;
this.snapshotId = null;
this.volumeSize = 0;
this.deleteOnTermination = true;
this.encrypted = false;
this.volumeType = null;
this.iops = null;
} else if (!inTagSet && !inProductCodes) {
try {
String region = getRequest() != null ? AWSUtils.findRegionInArgsOrNull(getRequest()) : null;

View File

@ -396,7 +396,7 @@ public class EBSBootEC2ApiLiveTest extends BaseComputeServiceContextLiveTest {
assertEquals(ebsImage.getRootDeviceType(), RootDeviceType.EBS);
assertEquals(ebsImage.getRootDeviceName(), "/dev/sda1");
assertEquals(ebsImage.getEbsBlockDevices().entrySet(),
ImmutableMap.of("/dev/sda1", new Image.EbsBlockDevice(snapshot.getId(), VOLUME_SIZE, true)).entrySet());
ImmutableMap.of("/dev/sda1", new Image.EbsBlockDevice(snapshot.getId(), VOLUME_SIZE, true, "standard", null, false)).entrySet());
}
private void tryToChangeStuff() {

View File

@ -182,7 +182,7 @@ public class AMIApiLiveTest extends BaseComputeServiceContextLiveTest {
// Register a new image...
ebsBackedImageId = client.registerUnixImageBackedByEbsInRegion(regionId, ebsBackedImageName, snapshot.getId(),
addNewBlockDevice("/dev/sda2", "myvirtual", 1).withDescription("adrian"));
addNewBlockDevice("/dev/sda2", "myvirtual", 1, false, "gp2", null, false).withDescription("adrian"));
imagesToDeregister.add(ebsBackedImageId);
final Image ebsBackedImage = getOnlyElement(client.describeImagesInRegion(regionId, imageIds(ebsBackedImageId)));
assertEquals(ebsBackedImage.getName(), ebsBackedImageName);
@ -192,8 +192,8 @@ public class AMIApiLiveTest extends BaseComputeServiceContextLiveTest {
assertEquals(ebsBackedImage.getDescription(), "adrian");
assertEquals(
ebsBackedImage.getEbsBlockDevices().entrySet(),
ImmutableMap.of("/dev/sda1", new Image.EbsBlockDevice(snapshot.getId(), snapshot.getVolumeSize(), true),
"/dev/sda2", new Image.EbsBlockDevice(null, 1, false)).entrySet());
ImmutableMap.of("/dev/sda1", new Image.EbsBlockDevice(snapshot.getId(), snapshot.getVolumeSize(), true, "standard", null, false),
"/dev/sda2", new Image.EbsBlockDevice(null, 1, false, "gp2", null, false)).entrySet());
// List of images after - should be one larger than before
int after = client.describeImagesInRegionWithFilter(regionId,

View File

@ -23,6 +23,7 @@ import org.jclouds.ec2.EC2Api;
import org.jclouds.ec2.domain.Snapshot;
import org.jclouds.ec2.domain.Volume;
import org.jclouds.ec2.internal.BaseEC2ApiExpectTest;
import org.jclouds.ec2.options.CreateVolumeOptions;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.rest.ResourceNotFoundException;
@ -36,14 +37,16 @@ import com.google.common.collect.ImmutableSet;
@Test(groups = "unit", testName = "EC2ElasticBlockStoreApiExpectTest")
public class EC2ElasticBlockStoreApiExpectTest extends BaseEC2ApiExpectTest<EC2Api> {
Volume creating = Volume.builder()
.id("vol-2a21e543")
.status(Volume.Status.CREATING)
.availabilityZone("us-east-1a")
.region("us-east-1")
.id("vol-2a21e543")
.size(1)
.createTime(dateService.iso8601DateParse("2009-12-28T05:42:53.000Z"))
.build();
.id("vol-2a21e543")
.status(Volume.Status.CREATING)
.availabilityZone("us-east-1a")
.region("us-east-1")
.id("vol-2a21e543")
.volumeType("standard")
.iops(0)
.size(1)
.createTime(dateService.iso8601DateParse("2009-12-28T05:42:53.000Z"))
.build();
public void testCreateVolumeInAvailabilityZone() {
Builder<HttpRequest, HttpResponse> builder = ImmutableMap.<HttpRequest, HttpResponse>builder();
@ -63,7 +66,38 @@ public class EC2ElasticBlockStoreApiExpectTest extends BaseEC2ApiExpectTest<EC2A
assertEquals(client.createVolumeInAvailabilityZone("us-east-1a", 4), creating);
}
public void testCreateVolumeInAvailabilityZoneWithOptions() {
Builder<HttpRequest, HttpResponse> builder = ImmutableMap.<HttpRequest, HttpResponse>builder();
builder.put(describeRegionsRequest, describeRegionsResponse);
builder.putAll(describeAvailabilityZonesRequestResponse);
builder.put(
HttpRequest.builder()
.method("POST")
.endpoint("https://ec2.us-east-1.amazonaws.com/")
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
.payload(payloadFromStringWithContentType("Action=CreateVolume" +
"&AvailabilityZone=us-east-1a" +
"&Iops=0" +
"&Signature=uI5tXrwV4zXB3uh0OP4RkfU2HMdQ2yICfpo4gKrajMI%3D" +
"&SignatureMethod=HmacSHA256" +
"&SignatureVersion=2" +
"&Size=4" +
"&Timestamp=2012-04-16T15%3A54%3A08.897Z" +
"&Version=2010-08-31" +
"&VolumeType=standard" +
"&AWSAccessKeyId=identity", "application/x-www-form-urlencoded")).build(),
HttpResponse.builder()
.statusCode(200)
.payload(payloadFromResource("/created_volume.xml")).build());
ElasticBlockStoreApi client = requestsSendResponses(builder.build()).getElasticBlockStoreApi().get();
assertEquals(client.createVolumeInAvailabilityZone("us-east-1a",
CreateVolumeOptions.Builder.withSize(4).isEncrypted(false).volumeType("standard").withIops(0)),
creating);
}
public void testCreateVolumeFromSnapshotInAvailabilityZoneEuSetsCorrectEndpoint() {
String region = "eu-west-1";
@ -72,16 +106,17 @@ public class EC2ElasticBlockStoreApiExpectTest extends BaseEC2ApiExpectTest<EC2A
builder.putAll(describeAvailabilityZonesRequestResponse);
builder.put(
formSigner.filter(HttpRequest.builder()
.method("POST")
.endpoint("https://ec2." + region + ".amazonaws.com/")
.addHeader("Host", "ec2." + region + ".amazonaws.com")
.addFormParam("Action", "CreateVolume")
.addFormParam("AvailabilityZone", "eu-west-1a")
.addFormParam("Size", "1")
.addFormParam("SnapshotId", "snap-8b7ffbdd").build()),
HttpResponse.builder()
.statusCode(200)
.payload(payloadFromResource("/created_volume.xml")).build());
.method("POST")
.endpoint("https://ec2." + region + ".amazonaws.com/")
.addHeader("Host", "ec2." + region + ".amazonaws.com")
.addFormParam("Action", "CreateVolume")
.addFormParam("AvailabilityZone", "eu-west-1a")
.addFormParam("Size", "1")
.addFormParam("SnapshotId", "snap-8b7ffbdd")
.build()),
HttpResponse.builder()
.statusCode(200)
.payload(payloadFromResource("/created_volume.xml")).build());
ElasticBlockStoreApi client = requestsSendResponses(builder.build()).getElasticBlockStoreApi().get();

View File

@ -17,6 +17,8 @@
package org.jclouds.ec2.features;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.jclouds.ec2.options.CreateVolumeOptions.Builder.fromSnapshotId;
import static org.jclouds.ec2.options.CreateVolumeOptions.Builder.volumeType;
import static org.jclouds.ec2.options.DescribeSnapshotsOptions.Builder.snapshotIds;
import static org.jclouds.util.Predicates2.retry;
import static org.testng.Assert.assertEquals;
@ -26,6 +28,11 @@ import static org.testng.Assert.assertNotNull;
import java.util.Set;
import java.util.SortedSet;
import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import org.jclouds.aws.AWSResponseException;
import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest;
import org.jclouds.ec2.EC2Api;
@ -38,12 +45,6 @@ import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
/**
* Tests behavior of {@code ElasticBlockStoreApi}
*/
@ -116,10 +117,11 @@ public class ElasticBlockStoreApiLiveTest extends BaseComputeServiceContextLiveT
@Test
void testCreateVolumeInAvailabilityZone() {
Volume expected = client.createVolumeInAvailabilityZone(defaultZone, 1);
Volume expected = client.createVolumeInAvailabilityZone(defaultZone,
volumeType("gp2"));
assertNotNull(expected);
assertEquals(expected.getAvailabilityZone(), defaultZone);
assertEquals(expected.getVolumeType(), "gp2");
this.volumeId = expected.getId();
Set<Volume> result = Sets.newLinkedHashSet(client.describeVolumesInRegion(defaultRegion, expected.getId()));
@ -127,6 +129,7 @@ public class ElasticBlockStoreApiLiveTest extends BaseComputeServiceContextLiveT
assertEquals(result.size(), 1);
Volume volume = result.iterator().next();
assertEquals(volume.getId(), expected.getId());
assertEquals(volume.getVolumeType(), expected.getVolumeType());
}
@Test(dependsOnMethods = "testCreateVolumeInAvailabilityZone")
@ -159,6 +162,24 @@ public class ElasticBlockStoreApiLiveTest extends BaseComputeServiceContextLiveT
client.deleteVolumeInRegion(snapshot.getRegion(), volume.getId());
}
@Test(dependsOnMethods = "testCreateSnapshotInRegion")
void testCreateVolumeFromSnapshotInAvailabilityZoneWithOptions() {
Volume volume = client.createVolumeInAvailabilityZone(defaultZone,
fromSnapshotId(snapshot.getId()));
assertNotNull(volume);
Predicate<Volume> availabile = retry(new VolumeAvailable(client), 600, 10, SECONDS);
assert availabile.apply(volume);
Volume result = Iterables.getOnlyElement(client.describeVolumesInRegion(snapshot.getRegion(), volume.getId()));
assertEquals(volume.getId(), result.getId());
assertEquals(volume.getSnapshotId(), snapshot.getId());
assertEquals(volume.getAvailabilityZone(), defaultZone);
assertEquals(result.getStatus(), Volume.Status.AVAILABLE);
client.deleteVolumeInRegion(snapshot.getRegion(), volume.getId());
}
@Test(dependsOnMethods = "testCreateSnapshotInRegion")
void testCreateVolumeFromSnapshotInAvailabilityZoneWithSize() {
Volume volume = client.createVolumeFromSnapshotInAvailabilityZone(defaultZone, 2, snapshot.getId());

View File

@ -0,0 +1,156 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.ec2.options;
import static org.jclouds.ec2.options.CreateVolumeOptions.Builder.fromSnapshotId;
import static org.jclouds.ec2.options.CreateVolumeOptions.Builder.isEncrypted;
import static org.jclouds.ec2.options.CreateVolumeOptions.Builder.volumeType;
import static org.jclouds.ec2.options.CreateVolumeOptions.Builder.withIops;
import static org.jclouds.ec2.options.CreateVolumeOptions.Builder.withSize;
import static org.testng.Assert.assertEquals;
import com.google.common.collect.ImmutableList;
import org.jclouds.http.options.HttpRequestOptions;
import org.testng.annotations.Test;
/**
* Tests possible uses of CreateVolumeOptions and CreateVolumeOptions.Builder.*
*/
public class CreateVolumeOptionsTest {
@Test
public void testAssignability() {
assert HttpRequestOptions.class.isAssignableFrom(CreateVolumeOptions.class);
assert !String.class.isAssignableFrom(CreateVolumeOptions.class);
}
@Test
public void testVolumeType() {
CreateVolumeOptions options = new CreateVolumeOptions();
options.volumeType("test");
assertEquals(options.buildFormParameters().get("VolumeType"),
ImmutableList.of("test"));
}
@Test
public void testNullVolumeType() {
CreateVolumeOptions options = new CreateVolumeOptions();
assertEquals(options.buildFormParameters().get("VolumeType"), ImmutableList.of());
}
@Test
public void testVolumeTypeStatic() {
CreateVolumeOptions options = volumeType("test");
assertEquals(options.buildFormParameters().get("VolumeType"),
ImmutableList.of("test"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testVolmeTypeNPE() {
volumeType(null);
}
@Test
public void testFromSnapshotId() {
CreateVolumeOptions options = new CreateVolumeOptions();
options.fromSnapshotId("test");
assertEquals(options.buildFormParameters().get("SnapshotId"),
ImmutableList.of("test"));
}
@Test
public void testNullFromSnapshotId() {
CreateVolumeOptions options = new CreateVolumeOptions();
assertEquals(options.buildFormParameters().get("SnapshotId"), ImmutableList.of());
}
@Test
public void testWithSnapshotIdStatic() {
CreateVolumeOptions options = fromSnapshotId("test");
assertEquals(options.buildFormParameters().get("SnapshotId"),
ImmutableList.of("test"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testFromSnapshotIdNPE() {
fromSnapshotId(null);
}
@Test
public void testWithIops() {
CreateVolumeOptions options = new CreateVolumeOptions();
options.withIops(5);
assertEquals(options.buildFormParameters().get("Iops"),
ImmutableList.of("5"));
}
@Test
public void testNullWithIops() {
CreateVolumeOptions options = new CreateVolumeOptions();
assertEquals(options.buildFormParameters().get("Iops"), ImmutableList.of());
}
@Test
public void testWithIopsStatic() {
CreateVolumeOptions options = withIops(5);
assertEquals(options.buildFormParameters().get("Iops"),
ImmutableList.of("5"));
}
@Test
public void testWithSize() {
CreateVolumeOptions options = new CreateVolumeOptions();
options.withSize(5);
assertEquals(options.buildFormParameters().get("Size"),
ImmutableList.of("5"));
}
@Test
public void testNullWithSize() {
CreateVolumeOptions options = new CreateVolumeOptions();
assertEquals(options.buildFormParameters().get("Size"), ImmutableList.of());
}
@Test
public void testWithSizeStatic() {
CreateVolumeOptions options = withSize(5);
assertEquals(options.buildFormParameters().get("Size"),
ImmutableList.of("5"));
}
@Test
public void testIsEncrypted() {
CreateVolumeOptions options = new CreateVolumeOptions();
options.isEncrypted(true);
assertEquals(options.buildFormParameters().get("Encrypted"),
ImmutableList.of("true"));
}
@Test
public void testNullIsEncrypted() {
CreateVolumeOptions options = new CreateVolumeOptions();
assertEquals(options.buildFormParameters().get("Encrypted"), ImmutableList.of());
}
@Test
public void testIsEncryptedStatic() {
CreateVolumeOptions options = isEncrypted(true);
assertEquals(options.buildFormParameters().get("Encrypted"),
ImmutableList.of("true"));
}
}

View File

@ -26,13 +26,12 @@ import static org.jclouds.ec2.options.RegisterImageBackedByEbsOptions.Builder.wi
import static org.jclouds.ec2.options.RegisterImageBackedByEbsOptions.Builder.withRamdisk;
import static org.testng.Assert.assertEquals;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
import org.jclouds.ec2.domain.Image.Architecture;
import org.jclouds.http.options.HttpRequestOptions;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
/**
* Tests possible uses of RegisterImageBackedByEbsOptions and
* RegisterImageBackedByEbsOptions.Builder.*
@ -188,6 +187,41 @@ public class RegisterImageBackedByEbsOptionsTest {
addBlockDeviceFromSnapshot(null, null, null);
}
@Test
public void testAdvancedAddBlockDeviceFromSnapshot() {
RegisterImageBackedByEbsOptions options = new RegisterImageBackedByEbsOptions();
options.addBlockDeviceFromSnapshot("deviceName", "virtualName", "snapshotId", true, "gp2", 0, false);
assertEquals(options.buildFormParameters().entries(), ImmutableMultimap.builder()
.put("BlockDeviceMapping.1.Ebs.DeleteOnTermination", "true")
.put("BlockDeviceMapping.1.Ebs.VolumeType", "gp2")
.put("BlockDeviceMapping.1.Ebs.Iops", "0")
.put("BlockDeviceMapping.1.DeviceName", "deviceName")
.put("BlockDeviceMapping.1.VirtualName", "virtualName")
.put("BlockDeviceMapping.1.Ebs.SnapshotId", "snapshotId")
.build()
.entries());
}
@Test
public void testAdvancedAddBlockDeviceFromSnapshotStatic() {
RegisterImageBackedByEbsOptions options = addBlockDeviceFromSnapshot("deviceName", "virtualName", "snapshotId", true, "gp2", 0, true);
assertEquals(options.buildFormParameters().entries(), ImmutableMultimap.builder()
.put("BlockDeviceMapping.1.Ebs.DeleteOnTermination", "true")
.put("BlockDeviceMapping.1.Ebs.VolumeType", "gp2")
.put("BlockDeviceMapping.1.Ebs.Iops", "0")
.put("BlockDeviceMapping.1.Ebs.Encrypted", "true")
.put("BlockDeviceMapping.1.DeviceName", "deviceName")
.put("BlockDeviceMapping.1.VirtualName", "virtualName")
.put("BlockDeviceMapping.1.Ebs.SnapshotId", "snapshotId")
.build()
.entries());
}
@Test(expectedExceptions = NullPointerException.class)
public void testAdvancedAddBlockDeviceFromSnapshotNPE() {
addBlockDeviceFromSnapshot(null, null, null, false, null, null, false);
}
@Test
public void testAddEphemeralBlockDeviceFromSnapshot() {
RegisterImageBackedByEbsOptions options = new RegisterImageBackedByEbsOptions();
@ -267,6 +301,41 @@ public class RegisterImageBackedByEbsOptionsTest {
addNewBlockDevice(null, null, 1);
}
@Test
public void testAdvancedAddNewBlockDevice() {
RegisterImageBackedByEbsOptions options = new RegisterImageBackedByEbsOptions();
options.addNewBlockDevice("deviceName", "virtualName", 5, true, "gp2", 0, true);
assertEquals(options.buildFormParameters().entries(), ImmutableMultimap.builder()
.put("BlockDeviceMapping.1.Ebs.DeleteOnTermination", "true")
.put("BlockDeviceMapping.1.Ebs.VolumeType", "gp2")
.put("BlockDeviceMapping.1.Ebs.Iops", "0")
.put("BlockDeviceMapping.1.Ebs.Encrypted", "true")
.put("BlockDeviceMapping.1.DeviceName", "deviceName")
.put("BlockDeviceMapping.1.VirtualName", "virtualName")
.put("BlockDeviceMapping.1.Ebs.VolumeSize", "5")
.build()
.entries());
}
@Test
public void testAdvancedAddNewBlockDeviceStatic() {
RegisterImageBackedByEbsOptions options = addNewBlockDevice("deviceName", "virtualName", 5, true, "gp2", 0, false);
assertEquals(options.buildFormParameters().entries(), ImmutableMultimap.builder()
.put("BlockDeviceMapping.1.Ebs.DeleteOnTermination", "true")
.put("BlockDeviceMapping.1.Ebs.VolumeType", "gp2")
.put("BlockDeviceMapping.1.Ebs.Iops", "0")
.put("BlockDeviceMapping.1.DeviceName", "deviceName")
.put("BlockDeviceMapping.1.VirtualName", "virtualName")
.put("BlockDeviceMapping.1.Ebs.VolumeSize", "5")
.build()
.entries());
}
@Test(expectedExceptions = NullPointerException.class)
public void testAdvancedAddNewBlockDeviceNPE() {
addNewBlockDevice(null, null, 5, false, null, null, false);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testAddNewBlockDeviceTooBig() {
addNewBlockDevice("deviceName", "virtualName", 1025);

View File

@ -207,7 +207,7 @@ public class RunInstancesOptionsTest {
@Test
public void testWithBlockDeviceMapping() {
BlockDeviceMapping mapping = new BlockDeviceMapping.MapNewVolumeToDevice("/dev/sda1", 120, true);
BlockDeviceMapping mapping = new BlockDeviceMapping.MapNewVolumeToDevice("/dev/sda1", 120, true, "gp2", 10, true);
RunInstancesOptions options = new RunInstancesOptions().withBlockDeviceMappings(ImmutableSet
.<BlockDeviceMapping> of(mapping));
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.DeviceName"),
@ -216,6 +216,12 @@ public class RunInstancesOptionsTest {
ImmutableList.of("120"));
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.DeleteOnTermination"),
ImmutableList.of("true"));
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.VolumeType"),
ImmutableList.of("gp2"));
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.Iops"),
ImmutableList.of("10"));
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.Encrypted"),
ImmutableList.of("true"));
}
@Test
@ -226,7 +232,7 @@ public class RunInstancesOptionsTest {
@Test
public void testWithBlockDeviceMappingStatic() {
BlockDeviceMapping mapping = new BlockDeviceMapping.MapNewVolumeToDevice("/dev/sda1", 120, true);
BlockDeviceMapping mapping = new BlockDeviceMapping.MapNewVolumeToDevice("/dev/sda1", 120, true, null, null, false);
RunInstancesOptions options = withBlockDeviceMappings(ImmutableSet
.<BlockDeviceMapping> of(mapping));
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.DeviceName"),
@ -235,6 +241,8 @@ public class RunInstancesOptionsTest {
ImmutableList.of("120"));
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.DeleteOnTermination"),
ImmutableList.of("true"));
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.VolumeType"),
ImmutableList.of());
}
@Test(expectedExceptions = NullPointerException.class)

View File

@ -41,9 +41,9 @@ public class CreateVolumeResponseHandlerTest extends BaseEC2HandlerTest {
InputStream is = getClass().getResourceAsStream("/created_volume.xml");
Volume expected = new Volume(Region.US_EAST_1, "vol-2a21e543", 1, null,
"us-east-1a", Volume.Status.CREATING, dateService
.iso8601DateParse("2009-12-28T05:42:53.000Z"), Sets
.<Attachment> newLinkedHashSet());
"us-east-1a", Volume.Status.CREATING, dateService
.iso8601DateParse("2009-12-28T05:42:53.000Z"), "standard", 0, false,
Sets.<Attachment> newLinkedHashSet());
CreateVolumeResponseHandler handler = injector.getInstance(CreateVolumeResponseHandler.class);
addDefaultRegionToHandler(handler);

View File

@ -18,6 +18,7 @@ package org.jclouds.ec2.xml;
import static com.google.common.collect.Iterables.get;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import java.io.InputStream;
import java.util.Set;
@ -83,17 +84,22 @@ public class DescribeImagesResponseHandlerTest {
public void testEBS() {
Set<Image> contents = ImmutableSet.of(new Image("us-east-1", Architecture.I386, "websrv_2009-12-10",
"Web Server AMI", "ami-246f8d4d", "706093390852/websrv_2009-12-10", "706093390852",
ImageState.AVAILABLE, "available", ImageType.MACHINE, true, Sets.<String> newHashSet(), null, "windows", null,
RootDeviceType.EBS, "/dev/sda1", ImmutableMap.<String, EbsBlockDevice> of("/dev/sda1",
new EbsBlockDevice("snap-d01272b9", 30, true), "xvdf", new EbsBlockDevice("snap-d31272ba", 250,
false)), ImmutableMap.<String, String> of(), VirtualizationType.HVM, Hypervisor.XEN));
"Web Server AMI", "ami-246f8d4d", "706093390852/websrv_2009-12-10", "706093390852",
ImageState.AVAILABLE, "available", ImageType.MACHINE, true, Sets.<String> newHashSet(), null, "windows", null,
RootDeviceType.EBS, "/dev/sda1",
ImmutableMap.<String, EbsBlockDevice> of("/dev/sda1",
new EbsBlockDevice("snap-d01272b9", 30, true, "standard", null, false),
"xvdf", new EbsBlockDevice("snap-d31272ba", 250, false, "standard", null, false)),
ImmutableMap.<String, String> of(), VirtualizationType.HVM, Hypervisor.XEN));
Set<Image> result = parseImages("/describe_images_ebs.xml");
assertEquals(result.toString(), contents.toString());
assertEquals(get(result, 0).getImageState(), ImageState.AVAILABLE);
assertEquals(get(result, 0).getRawState(), "available");
assertEquals(get(result, 0).getEbsBlockDevices().get("/dev/sda1").getVolumeType(), "standard");
assertEquals(get(result, 0).getEbsBlockDevices().get("/dev/sda1").isEncrypted(), false);
assertNull(get(result, 0).getEbsBlockDevices().get("/dev/sda1").getIops());
}
public void testTags() {

View File

@ -43,13 +43,14 @@ public class DescribeVolumesResponseHandlerTest extends BaseEC2HandlerTest {
Set<Volume> expected = Sets.newLinkedHashSet();
expected.add(new Volume(defaultRegion, "vol-2a21e543", 1, null, "us-east-1a",
Volume.Status.AVAILABLE, dateService.iso8601DateParse("2009-12-28T05:42:53.000Z"),
Sets.<Attachment> newLinkedHashSet()));
"standard", 0, false, Sets.<Attachment> newLinkedHashSet()));
expected.add(new Volume(defaultRegion, "vol-4282672b", 800, "snap-536d1b3a",
"us-east-1a", Volume.Status.IN_USE, dateService
.iso8601DateParse("2008-05-07T11:51:50.000Z"), Sets
.<Attachment> newHashSet(new Attachment(defaultRegion, "vol-4282672b", "i-6058a509",
"/dev/sdh", Attachment.Status.ATTACHED, dateService
.iso8601DateParse("2008-05-07T12:51:50.000Z")))));
"us-east-1a", Volume.Status.IN_USE, dateService
.iso8601DateParse("2008-05-07T11:51:50.000Z"),
"standard", 0, false,
Sets.<Attachment> newHashSet(new Attachment(defaultRegion, "vol-4282672b", "i-6058a509",
"/dev/sdh", Attachment.Status.ATTACHED, dateService
.iso8601DateParse("2008-05-07T12:51:50.000Z")))));
DescribeVolumesResponseHandler handler = injector
.getInstance(DescribeVolumesResponseHandler.class);

View File

@ -6,4 +6,7 @@
<availabilityZone>us-east-1a</availabilityZone>
<status>creating</status>
<createTime>2009-12-28T05:42:53.000Z</createTime>
<volumeType>standard</volumeType>
<iops>0</iops>
<encrypted>false</encrypted>
</CreateVolumeResponse>

View File

@ -23,6 +23,8 @@
<snapshotId>snap-d01272b9</snapshotId>
<volumeSize>30</volumeSize>
<deleteOnTermination>true</deleteOnTermination>
<volumeType>standard</volumeType>
<encrypted>false</encrypted>
</ebs>
</item>
<item>
@ -31,6 +33,8 @@
<snapshotId>snap-d31272ba</snapshotId>
<volumeSize>250</volumeSize>
<deleteOnTermination>false</deleteOnTermination>
<volumeType>standard</volumeType>
<encrypted>false</encrypted>
</ebs>
</item>
</blockDeviceMapping>

View File

@ -9,6 +9,9 @@
<availabilityZone>us-east-1a</availabilityZone>
<status>available</status>
<createTime>2009-12-28T05:42:53.000Z</createTime>
<volumeType>standard</volumeType>
<iops>0</iops>
<encrypted>false</encrypted>
<attachmentSet />
</item>
<item>
@ -18,6 +21,9 @@
<availabilityZone>us-east-1a</availabilityZone>
<status>in-use</status>
<createTime>2008-05-07T11:51:50.000Z</createTime>
<volumeType>standard</volumeType>
<iops>0</iops>
<encrypted>false</encrypted>
<attachmentSet>
<item>
<volumeId>vol-4282672b</volumeId>

View File

@ -9,6 +9,9 @@
<availabilityZone>us-east-1a</availabilityZone>
<status>in-use</status>
<createTime>2008-05-07T11:51:50.000Z</createTime>
<volumeType>standard</volumeType>
<iops>0</iops>
<encrypted>false</encrypted>
<attachmentSet />
</item>
</volumeSet>

View File

@ -138,12 +138,26 @@ public class LaunchSpecification {
public Builder mapEBSSnapshotToDevice(String deviceName, String snapshotId, @Nullable Integer sizeInGib,
boolean deleteOnTermination) {
blockDeviceMappings.add(new MapEBSSnapshotToDevice(deviceName, snapshotId, sizeInGib, deleteOnTermination));
return mapEBSSnapshotToDevice(deviceName, snapshotId, sizeInGib, deleteOnTermination, null, null, null);
}
public Builder mapEBSSnapshotToDevice(String deviceName, String snapshotId, @Nullable Integer sizeInGib,
boolean deleteOnTermination, @Nullable String volumeType,
@Nullable Integer iops, @Nullable Boolean encrypted) {
blockDeviceMappings.add(new MapEBSSnapshotToDevice(deviceName, snapshotId, sizeInGib, deleteOnTermination,
volumeType, iops, encrypted));
return this;
}
public Builder mapNewVolumeToDevice(String deviceName, int sizeInGib, boolean deleteOnTermination) {
blockDeviceMappings.add(new MapNewVolumeToDevice(deviceName, sizeInGib, deleteOnTermination));
return mapNewVolumeToDevice(deviceName, sizeInGib, deleteOnTermination, null, null, null);
}
public Builder mapNewVolumeToDevice(String deviceName, int sizeInGib, boolean deleteOnTermination,
@Nullable String volumeType, @Nullable Integer iops,
@Nullable Boolean encrypted) {
blockDeviceMappings.add(new MapNewVolumeToDevice(deviceName, sizeInGib, deleteOnTermination,
volumeType, iops, encrypted));
return this;
}

View File

@ -263,28 +263,29 @@ public class AWSAMIApiTest extends BaseAWSEC2ApiTest<AWSAMIApi> {
}
HttpRequest registerImageBackedByEBSOptions = HttpRequest.builder().method("POST")
.endpoint("https://ec2.us-east-1.amazonaws.com/")
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
.addFormParam("Action", "RegisterImage")
.addFormParam("BlockDeviceMapping.0.DeviceName", "/dev/sda1")
.addFormParam("BlockDeviceMapping.0.Ebs.SnapshotId", "snapshotId")
.addFormParam("BlockDeviceMapping.1.DeviceName", "/dev/device")
.addFormParam("BlockDeviceMapping.1.Ebs.DeleteOnTermination", "false")
.addFormParam("BlockDeviceMapping.1.Ebs.SnapshotId", "snapshot")
.addFormParam("BlockDeviceMapping.2.DeviceName", "/dev/newdevice")
.addFormParam("BlockDeviceMapping.2.Ebs.DeleteOnTermination", "false")
.addFormParam("BlockDeviceMapping.2.Ebs.VolumeSize", "100")
.addFormParam("BlockDeviceMapping.2.VirtualName", "newblock")
.addFormParam("Description", "description")
.addFormParam("Name", "imageName")
.addFormParam("RootDeviceName", "/dev/sda1").build();
.endpoint("https://ec2.us-east-1.amazonaws.com/")
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
.addFormParam("Action", "RegisterImage")
.addFormParam("BlockDeviceMapping.0.DeviceName", "/dev/sda1")
.addFormParam("BlockDeviceMapping.0.Ebs.SnapshotId", "snapshotId")
.addFormParam("BlockDeviceMapping.1.DeviceName", "/dev/device")
.addFormParam("BlockDeviceMapping.1.Ebs.DeleteOnTermination", "false")
.addFormParam("BlockDeviceMapping.1.Ebs.SnapshotId", "snapshot")
.addFormParam("BlockDeviceMapping.1.Ebs.VolumeType", "gp2")
.addFormParam("BlockDeviceMapping.2.DeviceName", "/dev/newdevice")
.addFormParam("BlockDeviceMapping.2.Ebs.DeleteOnTermination", "false")
.addFormParam("BlockDeviceMapping.2.Ebs.VolumeSize", "100")
.addFormParam("BlockDeviceMapping.2.VirtualName", "newblock")
.addFormParam("Description", "description")
.addFormParam("Name", "imageName")
.addFormParam("RootDeviceName", "/dev/sda1").build();
public void testRegisterImageBackedByEBSOptions() throws SecurityException, NoSuchMethodException, IOException {
Invokable<?, ?> method = method(AWSAMIApi.class, "registerUnixImageBackedByEbsInRegion", String.class,
String.class, String.class, RegisterImageBackedByEbsOptions[].class);
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "imageName", "snapshotId",
new RegisterImageBackedByEbsOptions().withDescription("description").addBlockDeviceFromSnapshot(
"/dev/device", null, "snapshot").addNewBlockDevice("/dev/newdevice", "newblock", 100)));
"/dev/device", null, "snapshot", false, "gp2", null, false).addNewBlockDevice("/dev/newdevice", "newblock", 100)));
request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);

View File

@ -331,7 +331,7 @@ public class AWSRunInstancesOptionsTest {
@Test
public void testWithBlockDeviceMapping() {
BlockDeviceMapping mapping = new BlockDeviceMapping.MapNewVolumeToDevice("/dev/sda1", 120, true);
BlockDeviceMapping mapping = new BlockDeviceMapping.MapNewVolumeToDevice("/dev/sda1", 120, true, "gp2", 10, true);
AWSRunInstancesOptions options = new AWSRunInstancesOptions().withBlockDeviceMappings(ImmutableSet
.<BlockDeviceMapping> of(mapping));
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.DeviceName"),
@ -340,6 +340,12 @@ public class AWSRunInstancesOptionsTest {
ImmutableList.of("120"));
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.DeleteOnTermination"),
ImmutableList.of("true"));
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.VolumeType"),
ImmutableList.of("gp2"));
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.Iops"),
ImmutableList.of("10"));
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.Ebs.Encrypted"),
ImmutableList.of("true"));
}
@Test
@ -350,7 +356,7 @@ public class AWSRunInstancesOptionsTest {
@Test
public void testWithBlockDeviceMappingStatic() {
BlockDeviceMapping mapping = new BlockDeviceMapping.MapNewVolumeToDevice("/dev/sda1", 120, true);
BlockDeviceMapping mapping = new BlockDeviceMapping.MapNewVolumeToDevice("/dev/sda1", 120, true, null, null, false);
AWSRunInstancesOptions options = withBlockDeviceMappings(ImmutableSet.<BlockDeviceMapping> of(mapping));
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.1.DeviceName"),
ImmutableList.of("/dev/sda1"));