Volume attachments to show in instance.
Volumes and Snapshots to be searchable by their id Placement of instance to match region connection Times for creation and attachment to show based on api call
This commit is contained in:
parent
3a81982cce
commit
2bb79824ce
@ -3,6 +3,7 @@ from __future__ import unicode_literals
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
import copy
|
import copy
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import itertools
|
import itertools
|
||||||
import re
|
import re
|
||||||
|
|
||||||
@ -97,6 +98,9 @@ from .utils import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def utc_date_and_time():
|
||||||
|
return datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||||
|
|
||||||
def validate_resource_ids(resource_ids):
|
def validate_resource_ids(resource_ids):
|
||||||
for resource_id in resource_ids:
|
for resource_id in resource_ids:
|
||||||
if not is_valid_resource_id(resource_id):
|
if not is_valid_resource_id(resource_id):
|
||||||
@ -309,14 +313,17 @@ class Instance(BotoInstance, TaggedEC2Resource):
|
|||||||
in_ec2_classic = not bool(self.subnet_id)
|
in_ec2_classic = not bool(self.subnet_id)
|
||||||
self.key_name = kwargs.get("key_name")
|
self.key_name = kwargs.get("key_name")
|
||||||
self.source_dest_check = "true"
|
self.source_dest_check = "true"
|
||||||
self.launch_time = datetime.utcnow().isoformat()
|
self.launch_time = utc_date_and_time()
|
||||||
associate_public_ip = kwargs.get("associate_public_ip", False)
|
associate_public_ip = kwargs.get("associate_public_ip", False)
|
||||||
if in_ec2_classic:
|
if in_ec2_classic:
|
||||||
# If we are in EC2-Classic, autoassign a public IP
|
# If we are in EC2-Classic, autoassign a public IP
|
||||||
associate_public_ip = True
|
associate_public_ip = True
|
||||||
|
|
||||||
self.block_device_mapping = BlockDeviceMapping()
|
self.block_device_mapping = BlockDeviceMapping()
|
||||||
self.block_device_mapping['/dev/sda1'] = BlockDeviceType(volume_id=random_volume_id())
|
# Default have an instance with root volume should you not wish to override with attach volume cmd.
|
||||||
|
# However this is a ghost volume and wont show up in get_all_volumes or snapshot-able.
|
||||||
|
self.block_device_mapping['/dev/sda1'] = BlockDeviceType(volume_id=random_volume_id(), status='attached',
|
||||||
|
attach_time=utc_date_and_time())
|
||||||
|
|
||||||
amis = self.ec2_backend.describe_images(filters={'image-id': image_id})
|
amis = self.ec2_backend.describe_images(filters={'image-id': image_id})
|
||||||
ami = amis[0] if amis else None
|
ami = amis[0] if amis else None
|
||||||
@ -343,6 +350,10 @@ class Instance(BotoInstance, TaggedEC2Resource):
|
|||||||
private_ip=kwargs.get("private_ip"),
|
private_ip=kwargs.get("private_ip"),
|
||||||
associate_public_ip=associate_public_ip)
|
associate_public_ip=associate_public_ip)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def get_block_device_mapping(self):
|
||||||
|
return self.block_device_mapping.items()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def private_ip(self):
|
def private_ip(self):
|
||||||
return self.nics[0].private_ip_address
|
return self.nics[0].private_ip_address
|
||||||
@ -1349,6 +1360,7 @@ class SecurityGroupIngress(object):
|
|||||||
class VolumeAttachment(object):
|
class VolumeAttachment(object):
|
||||||
def __init__(self, volume, instance, device):
|
def __init__(self, volume, instance, device):
|
||||||
self.volume = volume
|
self.volume = volume
|
||||||
|
self.attach_time = utc_date_and_time()
|
||||||
self.instance = instance
|
self.instance = instance
|
||||||
self.device = device
|
self.device = device
|
||||||
|
|
||||||
@ -1373,6 +1385,7 @@ class Volume(TaggedEC2Resource):
|
|||||||
self.id = volume_id
|
self.id = volume_id
|
||||||
self.size = size
|
self.size = size
|
||||||
self.zone = zone
|
self.zone = zone
|
||||||
|
self.create_time = utc_date_and_time()
|
||||||
self.attachment = None
|
self.attachment = None
|
||||||
self.ec2_backend = ec2_backend
|
self.ec2_backend = ec2_backend
|
||||||
|
|
||||||
@ -1404,6 +1417,7 @@ class Snapshot(TaggedEC2Resource):
|
|||||||
self.id = snapshot_id
|
self.id = snapshot_id
|
||||||
self.volume = volume
|
self.volume = volume
|
||||||
self.description = description
|
self.description = description
|
||||||
|
self.start_time = utc_date_and_time()
|
||||||
self.create_volume_permission_groups = set()
|
self.create_volume_permission_groups = set()
|
||||||
self.ec2_backend = ec2_backend
|
self.ec2_backend = ec2_backend
|
||||||
|
|
||||||
@ -1444,6 +1458,13 @@ class EBSBackend(object):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
volume.attachment = VolumeAttachment(volume, instance, device_path)
|
volume.attachment = VolumeAttachment(volume, instance, device_path)
|
||||||
|
# Modify instance to capture mount of block device.
|
||||||
|
bdt = BlockDeviceType(volume_id=volume_id, status=volume.status, size=volume.size,
|
||||||
|
attach_time=utc_date_and_time())
|
||||||
|
try:
|
||||||
|
instance.block_device_mapping[device_path] = bdt
|
||||||
|
except:
|
||||||
|
instance.block_device_mapping.setdefault(device_path, bdt)
|
||||||
return volume.attachment
|
return volume.attachment
|
||||||
|
|
||||||
def detach_volume(self, volume_id, instance_id, device_path):
|
def detach_volume(self, volume_id, instance_id, device_path):
|
||||||
|
@ -42,12 +42,22 @@ class ElasticBlockStore(BaseResponse):
|
|||||||
return DELETE_VOLUME_RESPONSE
|
return DELETE_VOLUME_RESPONSE
|
||||||
|
|
||||||
def describe_snapshots(self):
|
def describe_snapshots(self):
|
||||||
|
# querystring for multiple snapshotids results in SnapshotId.1, SnapshotId.2 etc
|
||||||
|
snapshot_ids = ','.join([','.join(s[1]) for s in self.querystring.items() if 'SnapshotId' in s[0]])
|
||||||
snapshots = self.ec2_backend.describe_snapshots()
|
snapshots = self.ec2_backend.describe_snapshots()
|
||||||
|
# Describe snapshots to handle filter on snapshot_ids
|
||||||
|
snapshots = [s for s in snapshots if s.id in snapshot_ids] if snapshot_ids else snapshots
|
||||||
|
# snapshots = self.ec2_backend.describe_snapshots()
|
||||||
template = self.response_template(DESCRIBE_SNAPSHOTS_RESPONSE)
|
template = self.response_template(DESCRIBE_SNAPSHOTS_RESPONSE)
|
||||||
return template.render(snapshots=snapshots)
|
return template.render(snapshots=snapshots)
|
||||||
|
|
||||||
def describe_volumes(self):
|
def describe_volumes(self):
|
||||||
|
# querystring for multiple volumeids results in VolumeId.1, VolumeId.2 etc
|
||||||
|
volume_ids = ','.join([','.join(v[1]) for v in self.querystring.items() if 'VolumeId' in v[0]])
|
||||||
volumes = self.ec2_backend.describe_volumes()
|
volumes = self.ec2_backend.describe_volumes()
|
||||||
|
# Describe volumes to handle filter on volume_ids
|
||||||
|
volumes = [v for v in volumes if v.id in volume_ids] if volume_ids else volumes
|
||||||
|
# volumes = self.ec2_backend.describe_volumes()
|
||||||
template = self.response_template(DESCRIBE_VOLUMES_RESPONSE)
|
template = self.response_template(DESCRIBE_VOLUMES_RESPONSE)
|
||||||
return template.render(volumes=volumes)
|
return template.render(volumes=volumes)
|
||||||
|
|
||||||
@ -103,7 +113,7 @@ CREATE_VOLUME_RESPONSE = """<CreateVolumeResponse xmlns="http://ec2.amazonaws.co
|
|||||||
<snapshotId/>
|
<snapshotId/>
|
||||||
<availabilityZone>{{ volume.zone.name }}</availabilityZone>
|
<availabilityZone>{{ volume.zone.name }}</availabilityZone>
|
||||||
<status>creating</status>
|
<status>creating</status>
|
||||||
<createTime>2013-10-04T17:38:53.000Z</createTime>
|
<createTime>{{ volume.create_time}}</createTime>
|
||||||
<volumeType>standard</volumeType>
|
<volumeType>standard</volumeType>
|
||||||
</CreateVolumeResponse>"""
|
</CreateVolumeResponse>"""
|
||||||
|
|
||||||
@ -117,7 +127,7 @@ DESCRIBE_VOLUMES_RESPONSE = """<DescribeVolumesResponse xmlns="http://ec2.amazon
|
|||||||
<snapshotId/>
|
<snapshotId/>
|
||||||
<availabilityZone>{{ volume.zone.name }}</availabilityZone>
|
<availabilityZone>{{ volume.zone.name }}</availabilityZone>
|
||||||
<status>{{ volume.status }}</status>
|
<status>{{ volume.status }}</status>
|
||||||
<createTime>2013-10-04T17:38:53.000Z</createTime>
|
<createTime>{{ volume.create_time}}</createTime>
|
||||||
<attachmentSet>
|
<attachmentSet>
|
||||||
{% if volume.attachment %}
|
{% if volume.attachment %}
|
||||||
<item>
|
<item>
|
||||||
@ -125,7 +135,7 @@ DESCRIBE_VOLUMES_RESPONSE = """<DescribeVolumesResponse xmlns="http://ec2.amazon
|
|||||||
<instanceId>{{ volume.attachment.instance.id }}</instanceId>
|
<instanceId>{{ volume.attachment.instance.id }}</instanceId>
|
||||||
<device>{{ volume.attachment.device }}</device>
|
<device>{{ volume.attachment.device }}</device>
|
||||||
<status>attached</status>
|
<status>attached</status>
|
||||||
<attachTime>2013-10-04T17:38:53.000Z</attachTime>
|
<attachTime>{{volume.attachment.attach_time}}</attachTime>
|
||||||
<deleteOnTermination>false</deleteOnTermination>
|
<deleteOnTermination>false</deleteOnTermination>
|
||||||
</item>
|
</item>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -157,7 +167,7 @@ ATTACHED_VOLUME_RESPONSE = """<AttachVolumeResponse xmlns="http://ec2.amazonaws.
|
|||||||
<instanceId>{{ attachment.instance.id }}</instanceId>
|
<instanceId>{{ attachment.instance.id }}</instanceId>
|
||||||
<device>{{ attachment.device }}</device>
|
<device>{{ attachment.device }}</device>
|
||||||
<status>attaching</status>
|
<status>attaching</status>
|
||||||
<attachTime>2013-10-04T17:38:53.000Z</attachTime>
|
<attachTime>{{attachment.attach_time}}</attachTime>
|
||||||
</AttachVolumeResponse>"""
|
</AttachVolumeResponse>"""
|
||||||
|
|
||||||
DETATCH_VOLUME_RESPONSE = """<DetachVolumeResponse xmlns="http://ec2.amazonaws.com/doc/2012-12-01/">
|
DETATCH_VOLUME_RESPONSE = """<DetachVolumeResponse xmlns="http://ec2.amazonaws.com/doc/2012-12-01/">
|
||||||
@ -174,7 +184,7 @@ CREATE_SNAPSHOT_RESPONSE = """<CreateSnapshotResponse xmlns="http://ec2.amazonaw
|
|||||||
<snapshotId>{{ snapshot.id }}</snapshotId>
|
<snapshotId>{{ snapshot.id }}</snapshotId>
|
||||||
<volumeId>{{ snapshot.volume.id }}</volumeId>
|
<volumeId>{{ snapshot.volume.id }}</volumeId>
|
||||||
<status>pending</status>
|
<status>pending</status>
|
||||||
<startTime>2013-10-04T17:38:53.000Z</startTime>
|
<startTime>{{ snapshot.start_time}}</startTime>
|
||||||
<progress>60%</progress>
|
<progress>60%</progress>
|
||||||
<ownerId>111122223333</ownerId>
|
<ownerId>111122223333</ownerId>
|
||||||
<volumeSize>{{ snapshot.volume.size }}</volumeSize>
|
<volumeSize>{{ snapshot.volume.size }}</volumeSize>
|
||||||
@ -189,7 +199,7 @@ DESCRIBE_SNAPSHOTS_RESPONSE = """<DescribeSnapshotsResponse xmlns="http://ec2.am
|
|||||||
<snapshotId>{{ snapshot.id }}</snapshotId>
|
<snapshotId>{{ snapshot.id }}</snapshotId>
|
||||||
<volumeId>{{ snapshot.volume.id }}</volumeId>
|
<volumeId>{{ snapshot.volume.id }}</volumeId>
|
||||||
<status>pending</status>
|
<status>pending</status>
|
||||||
<startTime>2013-10-04T17:38:53.000Z</startTime>
|
<startTime>{{ snapshot.start_time}}</startTime>
|
||||||
<progress>30%</progress>
|
<progress>30%</progress>
|
||||||
<ownerId>111122223333</ownerId>
|
<ownerId>111122223333</ownerId>
|
||||||
<volumeSize>{{ snapshot.volume.size }}</volumeSize>
|
<volumeSize>{{ snapshot.volume.size }}</volumeSize>
|
||||||
|
@ -206,7 +206,7 @@ EC2_RUN_INSTANCES = """<RunInstancesResponse xmlns="http://ec2.amazonaws.com/doc
|
|||||||
<instanceType>{{ instance.instance_type }}</instanceType>
|
<instanceType>{{ instance.instance_type }}</instanceType>
|
||||||
<launchTime>{{ instance.launch_time }}</launchTime>
|
<launchTime>{{ instance.launch_time }}</launchTime>
|
||||||
<placement>
|
<placement>
|
||||||
<availabilityZone>us-east-1b</availabilityZone>
|
<availabilityZone>{{ instance.placement}}</availabilityZone>
|
||||||
<groupName/>
|
<groupName/>
|
||||||
<tenancy>default</tenancy>
|
<tenancy>default</tenancy>
|
||||||
</placement>
|
</placement>
|
||||||
@ -331,7 +331,7 @@ EC2_DESCRIBE_INSTANCES = """<DescribeInstancesResponse xmlns='http://ec2.amazona
|
|||||||
<instanceType>{{ instance.instance_type }}</instanceType>
|
<instanceType>{{ instance.instance_type }}</instanceType>
|
||||||
<launchTime>{{ instance.launch_time }}</launchTime>
|
<launchTime>{{ instance.launch_time }}</launchTime>
|
||||||
<placement>
|
<placement>
|
||||||
<availabilityZone>us-west-2a</availabilityZone>
|
<availabilityZone>{{ instance.placement }}</availabilityZone>
|
||||||
<groupName/>
|
<groupName/>
|
||||||
<tenancy>default</tenancy>
|
<tenancy>default</tenancy>
|
||||||
</placement>
|
</placement>
|
||||||
@ -369,15 +369,18 @@ EC2_DESCRIBE_INSTANCES = """<DescribeInstancesResponse xmlns='http://ec2.amazona
|
|||||||
<rootDeviceType>ebs</rootDeviceType>
|
<rootDeviceType>ebs</rootDeviceType>
|
||||||
<rootDeviceName>/dev/sda1</rootDeviceName>
|
<rootDeviceName>/dev/sda1</rootDeviceName>
|
||||||
<blockDeviceMapping>
|
<blockDeviceMapping>
|
||||||
|
{% for device_name,deviceobject in instance.get_block_device_mapping %}
|
||||||
<item>
|
<item>
|
||||||
<deviceName>/dev/sda1</deviceName>
|
<deviceName>{{ device_name }}</deviceName>
|
||||||
<ebs>
|
<ebs>
|
||||||
<volumeId>{{ instance.block_device_mapping['/dev/sda1'].volume_id }}</volumeId>
|
<volumeId>{{ deviceobject.volume_id }}</volumeId>
|
||||||
<status>attached</status>
|
<status>{{ deviceobject.status }}</status>
|
||||||
<attachTime>2015-01-01T00:00:00.000Z</attachTime>
|
<attachTime>{{ deviceobject.attach_time }}</attachTime>
|
||||||
<deleteOnTermination>true</deleteOnTermination>
|
<deleteOnTermination>{{ deviceobject.delete_on_termination }}</deleteOnTermination>
|
||||||
|
<size>{{deviceobject.size}}</size>
|
||||||
</ebs>
|
</ebs>
|
||||||
</item>
|
</item>
|
||||||
|
{% endfor %}
|
||||||
</blockDeviceMapping>
|
</blockDeviceMapping>
|
||||||
<virtualizationType>{{ instance.virtualization_type }}</virtualizationType>
|
<virtualizationType>{{ instance.virtualization_type }}</virtualizationType>
|
||||||
<clientToken>ABCDE1234567890123</clientToken>
|
<clientToken>ABCDE1234567890123</clientToken>
|
||||||
@ -547,7 +550,7 @@ EC2_INSTANCE_STATUS = """<?xml version="1.0" encoding="UTF-8"?>
|
|||||||
{% for instance in instances %}
|
{% for instance in instances %}
|
||||||
<item>
|
<item>
|
||||||
<instanceId>{{ instance.id }}</instanceId>
|
<instanceId>{{ instance.id }}</instanceId>
|
||||||
<availabilityZone>us-east-1d</availabilityZone>
|
<availabilityZone>{{ instance.placement }}</availabilityZone>
|
||||||
<instanceState>
|
<instanceState>
|
||||||
<code>{{ instance.state_code }}</code>
|
<code>{{ instance.state_code }}</code>
|
||||||
<name>{{ instance.state }}</name>
|
<name>{{ instance.state }}</name>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user