EC2: Add iops to volume (#5776)
This commit is contained in:
parent
e5d40f63f8
commit
52891e1641
@ -19,6 +19,10 @@ from ..utils import (
|
||||
utc_date_and_time,
|
||||
)
|
||||
|
||||
IOPS_REQUIRED_VOLUME_TYPES = ["io1", "io2"]
|
||||
IOPS_SUPPORTED_VOLUME_TYPES = ["gp3", "io1", "io2"]
|
||||
GP3_DEFAULT_IOPS = 3000
|
||||
|
||||
|
||||
class VolumeModification(object):
|
||||
def __init__(self, volume, target_size=None, target_volume_type=None):
|
||||
@ -97,6 +101,7 @@ class Volume(TaggedEC2Resource, CloudFormationModel):
|
||||
encrypted=False,
|
||||
kms_key_id=None,
|
||||
volume_type=None,
|
||||
iops=None,
|
||||
):
|
||||
self.id = volume_id
|
||||
self.volume_type = volume_type or "gp2"
|
||||
@ -109,6 +114,7 @@ class Volume(TaggedEC2Resource, CloudFormationModel):
|
||||
self.encrypted = encrypted
|
||||
self.kms_key_id = kms_key_id
|
||||
self.modifications = []
|
||||
self.iops = iops
|
||||
|
||||
def modify(self, target_size=None, target_volume_type=None):
|
||||
modification = VolumeModification(
|
||||
@ -240,11 +246,19 @@ class EBSBackend:
|
||||
encrypted=False,
|
||||
kms_key_id=None,
|
||||
volume_type=None,
|
||||
iops=None,
|
||||
):
|
||||
if kms_key_id and not encrypted:
|
||||
raise InvalidParameterDependency("KmsKeyId", "Encrypted")
|
||||
if encrypted and not kms_key_id:
|
||||
kms_key_id = self._get_default_encryption_key()
|
||||
if volume_type in IOPS_REQUIRED_VOLUME_TYPES and not iops:
|
||||
raise InvalidParameterDependency("VolumeType", "Iops")
|
||||
elif volume_type == "gp3" and not iops:
|
||||
iops = GP3_DEFAULT_IOPS
|
||||
elif volume_type not in IOPS_SUPPORTED_VOLUME_TYPES and iops:
|
||||
raise InvalidParameterDependency("VolumeType", "Iops")
|
||||
|
||||
volume_id = random_volume_id()
|
||||
zone = self.get_zone_by_name(zone_name)
|
||||
if snapshot_id:
|
||||
@ -262,6 +276,7 @@ class EBSBackend:
|
||||
encrypted=encrypted,
|
||||
kms_key_id=kms_key_id,
|
||||
volume_type=volume_type,
|
||||
iops=iops,
|
||||
)
|
||||
self.volumes[volume_id] = volume
|
||||
return volume
|
||||
|
@ -199,6 +199,7 @@ class Instance(TaggedEC2Resource, BotoInstance, CloudFormationModel):
|
||||
delete_on_termination=False,
|
||||
kms_key_id=None,
|
||||
volume_type=None,
|
||||
iops=None,
|
||||
):
|
||||
volume = self.ec2_backend.create_volume(
|
||||
size=size,
|
||||
@ -207,6 +208,7 @@ class Instance(TaggedEC2Resource, BotoInstance, CloudFormationModel):
|
||||
encrypted=encrypted,
|
||||
kms_key_id=kms_key_id,
|
||||
volume_type=volume_type,
|
||||
iops=iops,
|
||||
)
|
||||
self.ec2_backend.attach_volume(
|
||||
volume.id, self.id, device_path, delete_on_termination
|
||||
|
@ -61,6 +61,7 @@ class ElasticBlockStore(EC2BaseResponse):
|
||||
volume_tags = tags.get("volume", {})
|
||||
encrypted = self._get_bool_param("Encrypted", if_none=False)
|
||||
kms_key_id = self._get_param("KmsKeyId")
|
||||
iops = self._get_param("Iops")
|
||||
if self.is_not_dryrun("CreateVolume"):
|
||||
volume = self.ec2_backend.create_volume(
|
||||
size=size,
|
||||
@ -69,6 +70,7 @@ class ElasticBlockStore(EC2BaseResponse):
|
||||
encrypted=encrypted,
|
||||
kms_key_id=kms_key_id,
|
||||
volume_type=volume_type,
|
||||
iops=iops,
|
||||
)
|
||||
volume.add_tags(volume_tags)
|
||||
template = self.response_template(CREATE_VOLUME_RESPONSE)
|
||||
@ -209,7 +211,7 @@ CREATE_VOLUME_RESPONSE = """<CreateVolumeResponse xmlns="http://ec2.amazonaws.co
|
||||
{% endif %}
|
||||
<availabilityZone>{{ volume.zone.name }}</availabilityZone>
|
||||
<status>creating</status>
|
||||
<createTime>{{ volume.create_time}}</createTime>
|
||||
<createTime>{{ volume.create_time }}</createTime>
|
||||
{% if volume.get_tags() %}
|
||||
<tagSet>
|
||||
{% for tag in volume.get_tags() %}
|
||||
@ -223,6 +225,9 @@ CREATE_VOLUME_RESPONSE = """<CreateVolumeResponse xmlns="http://ec2.amazonaws.co
|
||||
</tagSet>
|
||||
{% endif %}
|
||||
<volumeType>{{ volume.volume_type }}</volumeType>
|
||||
{% if volume.iops %}
|
||||
<iops>{{ volume.iops }}</iops>
|
||||
{% endif %}
|
||||
</CreateVolumeResponse>"""
|
||||
|
||||
DESCRIBE_VOLUMES_RESPONSE = """<DescribeVolumesResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
|
||||
@ -243,7 +248,7 @@ DESCRIBE_VOLUMES_RESPONSE = """<DescribeVolumesResponse xmlns="http://ec2.amazon
|
||||
{% endif %}
|
||||
<availabilityZone>{{ volume.zone.name }}</availabilityZone>
|
||||
<status>{{ volume.status }}</status>
|
||||
<createTime>{{ volume.create_time}}</createTime>
|
||||
<createTime>{{ volume.create_time }}</createTime>
|
||||
<attachmentSet>
|
||||
{% if volume.attachment %}
|
||||
<item>
|
||||
@ -269,6 +274,9 @@ DESCRIBE_VOLUMES_RESPONSE = """<DescribeVolumesResponse xmlns="http://ec2.amazon
|
||||
</tagSet>
|
||||
{% endif %}
|
||||
<volumeType>{{ volume.volume_type }}</volumeType>
|
||||
{% if volume.iops %}
|
||||
<iops>{{ volume.iops }}</iops>
|
||||
{% endif %}
|
||||
</item>
|
||||
{% endfor %}
|
||||
</volumeSet>
|
||||
|
@ -5,6 +5,7 @@ import sure # noqa # pylint: disable=unused-import
|
||||
from botocore.exceptions import ClientError
|
||||
from moto import mock_ec2
|
||||
from moto.core import DEFAULT_ACCOUNT_ID as OWNER_ID
|
||||
from moto.ec2.models.elastic_block_store import IOPS_REQUIRED_VOLUME_TYPES
|
||||
from moto.kms import mock_kms
|
||||
from tests import EXAMPLE_AMI_ID
|
||||
from uuid import uuid4
|
||||
@ -925,7 +926,7 @@ def test_kms_key_id_property_hidden_when_volume_not_encrypted():
|
||||
@mock_ec2
|
||||
def test_create_volume_with_standard_type():
|
||||
ec2 = boto3.client("ec2", region_name="us-east-1")
|
||||
volume = ec2.create_volume(AvailabilityZone="us-east-1a", Size=100, Iops=1000)
|
||||
volume = ec2.create_volume(AvailabilityZone="us-east-1a", Size=100)
|
||||
volume["VolumeType"].should.equal("gp2")
|
||||
|
||||
volume = ec2.describe_volumes(VolumeIds=[volume["VolumeId"]])["Volumes"][0]
|
||||
@ -936,9 +937,14 @@ def test_create_volume_with_standard_type():
|
||||
@mock_ec2
|
||||
def test_create_volume_with_non_standard_type(volume_type):
|
||||
ec2 = boto3.client("ec2", region_name="us-east-1")
|
||||
volume = ec2.create_volume(
|
||||
AvailabilityZone="us-east-1a", Size=100, Iops=1000, VolumeType=volume_type
|
||||
)
|
||||
if volume_type in IOPS_REQUIRED_VOLUME_TYPES:
|
||||
volume = ec2.create_volume(
|
||||
AvailabilityZone="us-east-1a", Size=100, Iops=3000, VolumeType=volume_type
|
||||
)
|
||||
else:
|
||||
volume = ec2.create_volume(
|
||||
AvailabilityZone="us-east-1a", Size=100, VolumeType=volume_type
|
||||
)
|
||||
volume["VolumeType"].should.equal(volume_type)
|
||||
|
||||
volume = ec2.describe_volumes(VolumeIds=[volume["VolumeId"]])["Volumes"][0]
|
||||
@ -1083,3 +1089,15 @@ def test_create_snapshots_multiple_volumes_without_boot():
|
||||
|
||||
snapshot2 = next(s for s in snapshots if s["VolumeId"] == volume2.volume_id)
|
||||
snapshot2.should.have.key("VolumeSize").equals(100)
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_create_volume_with_iops():
|
||||
ec2 = boto3.client("ec2", region_name="us-east-1")
|
||||
volume = ec2.create_volume(
|
||||
AvailabilityZone="us-east-1a", Size=10, VolumeType="gp3", Iops=4000
|
||||
)
|
||||
volume["Iops"].should.equal(4000)
|
||||
|
||||
volume = ec2.describe_volumes(VolumeIds=[volume["VolumeId"]])["Volumes"][0]
|
||||
volume["Iops"].should.equal(4000)
|
||||
|
Loading…
Reference in New Issue
Block a user