EC2: Streamline output of run_instances()/describe_instances() (#6906)

This commit is contained in:
Bert Blommers 2023-10-13 08:05:15 +00:00 committed by GitHub
parent de714eb4cc
commit f59e178f27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 77 additions and 179 deletions

View File

@ -47,6 +47,7 @@ class InstanceResponse(EC2BaseResponse):
account_id=self.current_account, account_id=self.current_account,
reservations=reservations_resp, reservations=reservations_resp,
next_token=next_token, next_token=next_token,
run_instances=False,
) )
.replace("True", "true") .replace("True", "true")
.replace("False", "false") .replace("False", "false")
@ -128,7 +129,9 @@ class InstanceResponse(EC2BaseResponse):
template = self.response_template(EC2_RUN_INSTANCES) template = self.response_template(EC2_RUN_INSTANCES)
return template.render( return template.render(
account_id=self.current_account, reservation=new_reservation account_id=self.current_account,
reservation=new_reservation,
run_instances=True,
) )
def terminate_instances(self) -> str: def terminate_instances(self) -> str:
@ -443,25 +446,20 @@ BLOCK_DEVICE_MAPPING_TEMPLATE = {
}, },
} }
EC2_RUN_INSTANCES = """<RunInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/"> INSTANCE_TEMPLATE = """<item>
<requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
<reservationId>{{ reservation.id }}</reservationId>
<ownerId>{{ account_id }}</ownerId>
<groupSet>
<item>
<groupId>sg-245f6a01</groupId>
<groupName>default</groupName>
</item>
</groupSet>
<instancesSet>
{% for instance in reservation.instances %}
<item>
<instanceId>{{ instance.id }}</instanceId> <instanceId>{{ instance.id }}</instanceId>
<imageId>{{ instance.image_id }}</imageId> <imageId>{{ instance.image_id }}</imageId>
{% if run_instances %}
<instanceState> <instanceState>
<code>0</code> <code>0</code>
<name>pending</name> <name>pending</name>
</instanceState> </instanceState>
{% else %}
<instanceState>
<code>{{ instance._state.code }}</code>
<name>{{ instance._state.name }}</name>
</instanceState>
{% endif %}
<privateDnsName>{{ instance.private_dns }}</privateDnsName> <privateDnsName>{{ instance.private_dns }}</privateDnsName>
<publicDnsName>{{ instance.public_dns }}</publicDnsName> <publicDnsName>{{ instance.public_dns }}</publicDnsName>
<dnsName>{{ instance.public_dns }}</dnsName> <dnsName>{{ instance.public_dns }}</dnsName>
@ -509,8 +507,12 @@ EC2_RUN_INSTANCES = """<RunInstancesResponse xmlns="http://ec2.amazonaws.com/doc
<groupSet> <groupSet>
{% for group in instance.dynamic_group_list %} {% for group in instance.dynamic_group_list %}
<item> <item>
{% if group.id %}
<groupId>{{ group.id }}</groupId> <groupId>{{ group.id }}</groupId>
<groupName>{{ group.name }}</groupName> <groupName>{{ group.name }}</groupName>
{% else %}
<groupId>{{ group }}</groupId>
{% endif %}
</item> </item>
{% endfor %} {% endfor %}
</groupSet> </groupSet>
@ -518,24 +520,47 @@ EC2_RUN_INSTANCES = """<RunInstancesResponse xmlns="http://ec2.amazonaws.com/doc
<platform>{{ instance.platform }}</platform> <platform>{{ instance.platform }}</platform>
{% endif %} {% endif %}
<virtualizationType>{{ instance.virtualization_type }}</virtualizationType> <virtualizationType>{{ instance.virtualization_type }}</virtualizationType>
<stateReason>
<code>{{ instance._state_reason.code }}</code>
<message>{{ instance._state_reason.message }}</message>
</stateReason>
<architecture>{{ instance.architecture }}</architecture> <architecture>{{ instance.architecture }}</architecture>
<kernelId>{{ instance.kernel }}</kernelId> <kernelId>{{ instance.kernel }}</kernelId>
<clientToken/> <rootDeviceType>ebs</rootDeviceType>
<rootDeviceName>/dev/sda1</rootDeviceName>
<blockDeviceMapping>
{% for device_name,deviceobject in instance.get_block_device_mapping %}
<item>
<deviceName>{{ device_name }}</deviceName>
<ebs>
<volumeId>{{ deviceobject.volume_id }}</volumeId>
<status>{{ deviceobject.status }}</status>
<attachTime>{{ deviceobject.attach_time }}</attachTime>
<deleteOnTermination>{{ deviceobject.delete_on_termination }}</deleteOnTermination>
<size>{{deviceobject.size}}</size>
</ebs>
</item>
{% endfor %}
</blockDeviceMapping>
<clientToken>ABCDE{{ account_id }}3</clientToken>
<hypervisor>xen</hypervisor> <hypervisor>xen</hypervisor>
<ebsOptimized>false</ebsOptimized>
{% if instance.hibernation_options %} {% if instance.hibernation_options %}
<hibernationOptions> <hibernationOptions>
<configured>{{ instance.hibernation_options.get("Configured") }}</configured> <configured>{{ instance.hibernation_options.get("Configured") }}</configured>
</hibernationOptions> </hibernationOptions>
{% endif %} {% endif %}
{% if instance.get_tags() %}
<tagSet> <tagSet>
{% for tag in instance.get_tags() %} {% for tag in instance.get_tags() %}
<item> <item>
<resourceId>{{ tag.resource_id }}</resourceId>
<resourceType>{{ tag.resource_type }}</resourceType>
<key>{{ tag.key }}</key> <key>{{ tag.key }}</key>
<value>{{ tag.value }}</value> <value>{{ tag.value }}</value>
</item> </item>
{% endfor %} {% endfor %}
</tagSet> </tagSet>
{% endif %}
<networkInterfaceSet> <networkInterfaceSet>
{% for nic in instance.nics.values() %} {% for nic in instance.nics.values() %}
<item> <item>
@ -553,8 +578,12 @@ EC2_RUN_INSTANCES = """<RunInstancesResponse xmlns="http://ec2.amazonaws.com/doc
<groupSet> <groupSet>
{% for group in nic.group_set %} {% for group in nic.group_set %}
<item> <item>
<groupId>{{ group.id }}</groupId> {% if group.id %}
<groupName>{{ group.name }}</groupName> <groupId>{{ group.id }}</groupId>
<groupName>{{ group.name }}</groupName>
{% else %}
<groupId>{{ group }}</groupId>
{% endif %}
</item> </item>
{% endfor %} {% endfor %}
</groupSet> </groupSet>
@ -586,12 +615,31 @@ EC2_RUN_INSTANCES = """<RunInstancesResponse xmlns="http://ec2.amazonaws.com/doc
</item> </item>
{% endfor %} {% endfor %}
</networkInterfaceSet> </networkInterfaceSet>
</item> </item>"""
EC2_RUN_INSTANCES = (
"""<RunInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
<requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
<reservationId>{{ reservation.id }}</reservationId>
<ownerId>{{ account_id }}</ownerId>
<groupSet>
<item>
<groupId>sg-245f6a01</groupId>
<groupName>default</groupName>
</item>
</groupSet>
<instancesSet>
{% for instance in reservation.instances %}
"""
+ INSTANCE_TEMPLATE
+ """
{% endfor %} {% endfor %}
</instancesSet> </instancesSet>
</RunInstancesResponse>""" </RunInstancesResponse>"""
)
EC2_DESCRIBE_INSTANCES = """<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/"> EC2_DESCRIBE_INSTANCES = (
"""<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
<requestId>fdcdcab1-ae5c-489e-9c33-4637c5dda355</requestId> <requestId>fdcdcab1-ae5c-489e-9c33-4637c5dda355</requestId>
<reservationSet> <reservationSet>
{% for reservation in reservations %} {% for reservation in reservations %}
@ -612,165 +660,9 @@ EC2_DESCRIBE_INSTANCES = """<DescribeInstancesResponse xmlns="http://ec2.amazona
</groupSet> </groupSet>
<instancesSet> <instancesSet>
{% for instance in reservation.instances %} {% for instance in reservation.instances %}
<item> """
<instanceId>{{ instance.id }}</instanceId> + INSTANCE_TEMPLATE
<imageId>{{ instance.image_id }}</imageId> + """
<instanceState>
<code>{{ instance._state.code }}</code>
<name>{{ instance._state.name }}</name>
</instanceState>
<privateDnsName>{{ instance.private_dns }}</privateDnsName>
<publicDnsName>{{ instance.public_dns }}</publicDnsName>
<dnsName>{{ instance.public_dns }}</dnsName>
<reason>{{ instance._reason }}</reason>
{% if instance.key_name is not none %}
<keyName>{{ instance.key_name }}</keyName>
{% endif %}
<ebsOptimized>{{ instance.ebs_optimized }}</ebsOptimized>
<amiLaunchIndex>{{ instance.ami_launch_index }}</amiLaunchIndex>
<productCodes/>
<instanceType>{{ instance.instance_type }}</instanceType>
{% if instance.iam_instance_profile %}
<iamInstanceProfile>
<arn>{{ instance.iam_instance_profile['Arn'] }}</arn>
<id>{{ instance.iam_instance_profile['Id'] }}</id>
</iamInstanceProfile>
{% endif %}
<launchTime>{{ instance.launch_time }}</launchTime>
{% if instance.lifecycle %}
<instanceLifecycle>{{ instance.lifecycle }}</instanceLifecycle>
{% endif %}
<placement>
{% if instance.placement_hostid %}<hostId>{{ instance.placement_hostid }}</hostId>{% endif %}
<availabilityZone>{{ instance.placement }}</availabilityZone>
<groupName/>
<tenancy>default</tenancy>
</placement>
{% if instance.platform %}
<platform>{{ instance.platform }}</platform>
{% endif %}
<monitoring>
<state>{{ instance.monitoring_state }}</state>
</monitoring>
{% if instance.subnet_id %}
<subnetId>{{ instance.subnet_id }}</subnetId>
{% elif instance.nics[0].subnet.id %}
<subnetId>{{ instance.nics[0].subnet.id }}</subnetId>
{% endif %}
{% if instance.vpc_id %}
<vpcId>{{ instance.vpc_id }}</vpcId>
{% elif instance.nics[0].subnet.vpc_id %}
<vpcId>{{ instance.nics[0].subnet.vpc_id }}</vpcId>
{% endif %}
<privateIpAddress>{{ instance.private_ip }}</privateIpAddress>
{% if instance.nics[0].public_ip %}
<ipAddress>{{ instance.nics[0].public_ip }}</ipAddress>
{% endif %}
<sourceDestCheck>{{ instance.source_dest_check }}</sourceDestCheck>
<groupSet>
{% for group in instance.dynamic_group_list %}
<item>
{% if group.id %}
<groupId>{{ group.id }}</groupId>
<groupName>{{ group.name }}</groupName>
{% else %}
<groupId>{{ group }}</groupId>
{% endif %}
</item>
{% endfor %}
</groupSet>
<stateReason>
<code>{{ instance._state_reason.code }}</code>
<message>{{ instance._state_reason.message }}</message>
</stateReason>
<architecture>{{ instance.architecture }}</architecture>
<kernelId>{{ instance.kernel }}</kernelId>
<rootDeviceType>ebs</rootDeviceType>
<rootDeviceName>/dev/sda1</rootDeviceName>
<blockDeviceMapping>
{% for device_name,deviceobject in instance.get_block_device_mapping %}
<item>
<deviceName>{{ device_name }}</deviceName>
<ebs>
<volumeId>{{ deviceobject.volume_id }}</volumeId>
<status>{{ deviceobject.status }}</status>
<attachTime>{{ deviceobject.attach_time }}</attachTime>
<deleteOnTermination>{{ deviceobject.delete_on_termination }}</deleteOnTermination>
<size>{{deviceobject.size}}</size>
</ebs>
</item>
{% endfor %}
</blockDeviceMapping>
<virtualizationType>{{ instance.virtualization_type }}</virtualizationType>
<clientToken>ABCDE{{ account_id }}3</clientToken>
{% if instance.get_tags() %}
<tagSet>
{% for tag in instance.get_tags() %}
<item>
<resourceId>{{ tag.resource_id }}</resourceId>
<resourceType>{{ tag.resource_type }}</resourceType>
<key>{{ tag.key }}</key>
<value>{{ tag.value }}</value>
</item>
{% endfor %}
</tagSet>
{% endif %}
<hypervisor>xen</hypervisor>
<networkInterfaceSet>
{% for nic in instance.nics.values() %}
<item>
<networkInterfaceId>{{ nic.id }}</networkInterfaceId>
{% if nic.subnet %}
<subnetId>{{ nic.subnet.id }}</subnetId>
<vpcId>{{ nic.subnet.vpc_id }}</vpcId>
{% endif %}
<description>Primary network interface</description>
<ownerId>{{ account_id }}</ownerId>
<status>in-use</status>
<macAddress>1b:2b:3c:4d:5e:6f</macAddress>
<privateIpAddress>{{ nic.private_ip_address }}</privateIpAddress>
<sourceDestCheck>{{ instance.source_dest_check }}</sourceDestCheck>
<groupSet>
{% for group in nic.group_set %}
<item>
{% if group.id %}
<groupId>{{ group.id }}</groupId>
<groupName>{{ group.name }}</groupName>
{% else %}
<groupId>{{ group }}</groupId>
{% endif %}
</item>
{% endfor %}
</groupSet>
<attachment>
<attachmentId>{{ nic.attachment_id }}</attachmentId>
<deviceIndex>{{ nic.device_index }}</deviceIndex>
<status>attached</status>
<attachTime>2015-01-01T00:00:00Z</attachTime>
<deleteOnTermination>true</deleteOnTermination>
</attachment>
{% if nic.public_ip %}
<association>
<publicIp>{{ nic.public_ip }}</publicIp>
<ipOwnerId>{{ account_id }}</ipOwnerId>
</association>
{% endif %}
<privateIpAddressesSet>
<item>
<privateIpAddress>{{ nic.private_ip_address }}</privateIpAddress>
<primary>true</primary>
{% if nic.public_ip %}
<association>
<publicIp>{{ nic.public_ip }}</publicIp>
<ipOwnerId>{{ account_id }}</ipOwnerId>
</association>
{% endif %}
</item>
</privateIpAddressesSet>
</item>
{% endfor %}
</networkInterfaceSet>
</item>
{% endfor %} {% endfor %}
</instancesSet> </instancesSet>
</item> </item>
@ -780,6 +672,7 @@ EC2_DESCRIBE_INSTANCES = """<DescribeInstancesResponse xmlns="http://ec2.amazona
<nextToken>{{ next_token }}</nextToken> <nextToken>{{ next_token }}</nextToken>
{% endif %} {% endif %}
</DescribeInstancesResponse>""" </DescribeInstancesResponse>"""
)
EC2_TERMINATE_INSTANCES = """ EC2_TERMINATE_INSTANCES = """
<TerminateInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/"> <TerminateInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">

View File

@ -1192,6 +1192,7 @@ def test_run_instance_with_security_group_id():
@mock_ec2 @mock_ec2
@pytest.mark.parametrize("hibernate", [True, False]) @pytest.mark.parametrize("hibernate", [True, False])
def test_run_instance_with_additional_args(hibernate): def test_run_instance_with_additional_args(hibernate):
client = boto3.client("ec2", region_name="us-east-1")
ec2 = boto3.resource("ec2", region_name="us-east-1") ec2 = boto3.resource("ec2", region_name="us-east-1")
instance = ec2.create_instances( instance = ec2.create_instances(
ImageId=EXAMPLE_AMI_ID, ImageId=EXAMPLE_AMI_ID,
@ -1206,6 +1207,10 @@ def test_run_instance_with_additional_args(hibernate):
assert instance.placement["AvailabilityZone"] == "us-east-1b" assert instance.placement["AvailabilityZone"] == "us-east-1b"
assert instance.hibernation_options == {"Configured": hibernate} assert instance.hibernation_options == {"Configured": hibernate}
reservations = client.describe_instances(InstanceIds=[instance.id])["Reservations"]
instance = reservations[0]["Instances"][0]
assert instance["HibernationOptions"] == {"Configured": hibernate}
@mock_ec2 @mock_ec2
def test_run_instance_with_default_placement(): def test_run_instance_with_default_placement():