EC2: create_volume(): support Throughput-parameter (#6379)

This commit is contained in:
Hisashi Kamezawa 2023-06-08 04:35:57 -07:00 committed by GitHub
parent 08e509506a
commit 681873d177
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 0 deletions

View File

@ -23,6 +23,7 @@ from ..utils import (
IOPS_REQUIRED_VOLUME_TYPES = ["io1", "io2"] IOPS_REQUIRED_VOLUME_TYPES = ["io1", "io2"]
IOPS_SUPPORTED_VOLUME_TYPES = ["gp3", "io1", "io2"] IOPS_SUPPORTED_VOLUME_TYPES = ["gp3", "io1", "io2"]
THROUGHPUT_SUPPORTED_VOLUME_TYPES = ["gp3"]
GP3_DEFAULT_IOPS = 3000 GP3_DEFAULT_IOPS = 3000
@ -114,6 +115,7 @@ class Volume(TaggedEC2Resource, CloudFormationModel):
kms_key_id: Optional[str] = None, kms_key_id: Optional[str] = None,
volume_type: Optional[str] = None, volume_type: Optional[str] = None,
iops: Optional[int] = None, iops: Optional[int] = None,
throughput: Optional[int] = None,
): ):
self.id = volume_id self.id = volume_id
self.volume_type = volume_type or "gp2" self.volume_type = volume_type or "gp2"
@ -127,6 +129,7 @@ class Volume(TaggedEC2Resource, CloudFormationModel):
self.kms_key_id = kms_key_id self.kms_key_id = kms_key_id
self.modifications: List[VolumeModification] = [] self.modifications: List[VolumeModification] = []
self.iops = iops self.iops = iops
self.throughput = throughput
def modify( def modify(
self, self,
@ -272,6 +275,7 @@ class EBSBackend:
kms_key_id: Optional[str] = None, kms_key_id: Optional[str] = None,
volume_type: Optional[str] = None, volume_type: Optional[str] = None,
iops: Optional[int] = None, iops: Optional[int] = None,
throughput: Optional[int] = None,
) -> Volume: ) -> Volume:
if kms_key_id and not encrypted: if kms_key_id and not encrypted:
raise InvalidParameterDependency("KmsKeyId", "Encrypted") raise InvalidParameterDependency("KmsKeyId", "Encrypted")
@ -283,6 +287,8 @@ class EBSBackend:
iops = GP3_DEFAULT_IOPS iops = GP3_DEFAULT_IOPS
elif volume_type not in IOPS_SUPPORTED_VOLUME_TYPES and iops: elif volume_type not in IOPS_SUPPORTED_VOLUME_TYPES and iops:
raise InvalidParameterDependency("VolumeType", "Iops") raise InvalidParameterDependency("VolumeType", "Iops")
if volume_type not in THROUGHPUT_SUPPORTED_VOLUME_TYPES and throughput:
raise InvalidParameterDependency("VolumeType", "Throughput")
volume_id = random_volume_id() volume_id = random_volume_id()
zone = self.get_zone_by_name(zone_name) # type: ignore[attr-defined] zone = self.get_zone_by_name(zone_name) # type: ignore[attr-defined]
@ -302,6 +308,7 @@ class EBSBackend:
kms_key_id=kms_key_id, kms_key_id=kms_key_id,
volume_type=volume_type, volume_type=volume_type,
iops=iops, iops=iops,
throughput=throughput,
) )
self.volumes[volume_id] = volume self.volumes[volume_id] = volume
return volume return volume

View File

@ -67,6 +67,7 @@ class ElasticBlockStore(EC2BaseResponse):
encrypted = self._get_bool_param("Encrypted", if_none=False) encrypted = self._get_bool_param("Encrypted", if_none=False)
kms_key_id = self._get_param("KmsKeyId") kms_key_id = self._get_param("KmsKeyId")
iops = self._get_param("Iops") iops = self._get_param("Iops")
throughput = self._get_param("Throughput")
self.error_on_dryrun() self.error_on_dryrun()
@ -78,6 +79,7 @@ class ElasticBlockStore(EC2BaseResponse):
kms_key_id=kms_key_id, kms_key_id=kms_key_id,
volume_type=volume_type, volume_type=volume_type,
iops=iops, iops=iops,
throughput=throughput,
) )
volume.add_tags(volume_tags) volume.add_tags(volume_tags)
template = self.response_template(CREATE_VOLUME_RESPONSE) template = self.response_template(CREATE_VOLUME_RESPONSE)
@ -246,6 +248,9 @@ CREATE_VOLUME_RESPONSE = """<CreateVolumeResponse xmlns="http://ec2.amazonaws.co
{% if volume.iops %} {% if volume.iops %}
<iops>{{ volume.iops }}</iops> <iops>{{ volume.iops }}</iops>
{% endif %} {% endif %}
{% if volume.throughput %}
<throughput>{{ volume.throughput }}</throughput>
{% endif %}
</CreateVolumeResponse>""" </CreateVolumeResponse>"""
DESCRIBE_VOLUMES_RESPONSE = """<DescribeVolumesResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/"> DESCRIBE_VOLUMES_RESPONSE = """<DescribeVolumesResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
@ -295,6 +300,9 @@ DESCRIBE_VOLUMES_RESPONSE = """<DescribeVolumesResponse xmlns="http://ec2.amazon
{% if volume.iops %} {% if volume.iops %}
<iops>{{ volume.iops }}</iops> <iops>{{ volume.iops }}</iops>
{% endif %} {% endif %}
{% if volume.throughput %}
<throughput>{{ volume.throughput }}</throughput>
{% endif %}
</item> </item>
{% endfor %} {% endfor %}
</volumeSet> </volumeSet>

View File

@ -1101,3 +1101,26 @@ def test_create_volume_with_iops():
volume = ec2.describe_volumes(VolumeIds=[volume["VolumeId"]])["Volumes"][0] volume = ec2.describe_volumes(VolumeIds=[volume["VolumeId"]])["Volumes"][0]
volume["Iops"].should.equal(4000) volume["Iops"].should.equal(4000)
@mock_ec2
def test_create_volume_with_throughput():
ec2 = boto3.client("ec2", region_name="us-east-1")
volume = ec2.create_volume(
AvailabilityZone="us-east-1a", Size=10, VolumeType="gp3", Throughput=200
)
volume["Throughput"].should.equal(200)
volume = ec2.describe_volumes(VolumeIds=[volume["VolumeId"]])["Volumes"][0]
volume["Throughput"].should.equal(200)
@mock_ec2
def test_create_volume_with_throughput_fails():
resource = boto3.resource("ec2", region_name="us-east-1")
with pytest.raises(ClientError) as ex:
resource.create_volume(
AvailabilityZone="us-east-1a", Size=10, VolumeType="gp2", Throughput=200
)
ex.value.response["Error"]["Code"].should.equal("InvalidParameterDependency")
ex.value.response["Error"]["Message"].should.contain("Throughput")