from __future__ import unicode_literals from moto.core.responses import BaseResponse from moto.ec2.utils import filters_from_querystring class ElasticBlockStore(BaseResponse): def attach_volume(self): volume_id = self.querystring.get('VolumeId')[0] instance_id = self.querystring.get('InstanceId')[0] device_path = self.querystring.get('Device')[0] attachment = self.ec2_backend.attach_volume(volume_id, instance_id, device_path) template = self.response_template(ATTACHED_VOLUME_RESPONSE) return template.render(attachment=attachment) def copy_snapshot(self): raise NotImplementedError('ElasticBlockStore.copy_snapshot is not yet implemented') def create_snapshot(self): description = None if 'Description' in self.querystring: description = self.querystring.get('Description')[0] volume_id = self.querystring.get('VolumeId')[0] snapshot = self.ec2_backend.create_snapshot(volume_id, description) template = self.response_template(CREATE_SNAPSHOT_RESPONSE) return template.render(snapshot=snapshot) def create_volume(self): size = self._get_param('Size') zone = self._get_param('AvailabilityZone') snapshot_id = self._get_param('SnapshotId') encrypted = self._get_param('Encrypted') volume = self.ec2_backend.create_volume(size, zone, snapshot_id, encrypted) template = self.response_template(CREATE_VOLUME_RESPONSE) return template.render(volume=volume) def delete_snapshot(self): snapshot_id = self.querystring.get('SnapshotId')[0] self.ec2_backend.delete_snapshot(snapshot_id) return DELETE_SNAPSHOT_RESPONSE def delete_volume(self): volume_id = self.querystring.get('VolumeId')[0] self.ec2_backend.delete_volume(volume_id) return DELETE_VOLUME_RESPONSE def describe_snapshots(self): filters = filters_from_querystring(self.querystring) # 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(filters=filters) # 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 template = self.response_template(DESCRIBE_SNAPSHOTS_RESPONSE) return template.render(snapshots=snapshots) def describe_volumes(self): filters = filters_from_querystring(self.querystring) # 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(filters=filters) # 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 template = self.response_template(DESCRIBE_VOLUMES_RESPONSE) return template.render(volumes=volumes) def describe_volume_attribute(self): raise NotImplementedError('ElasticBlockStore.describe_volume_attribute is not yet implemented') def describe_volume_status(self): raise NotImplementedError('ElasticBlockStore.describe_volume_status is not yet implemented') def detach_volume(self): volume_id = self.querystring.get('VolumeId')[0] instance_id = self.querystring.get('InstanceId')[0] device_path = self.querystring.get('Device')[0] attachment = self.ec2_backend.detach_volume(volume_id, instance_id, device_path) template = self.response_template(DETATCH_VOLUME_RESPONSE) return template.render(attachment=attachment) def enable_volume_io(self): raise NotImplementedError('ElasticBlockStore.enable_volume_io is not yet implemented') def import_volume(self): raise NotImplementedError('ElasticBlockStore.import_volume is not yet implemented') def describe_snapshot_attribute(self): snapshot_id = self.querystring.get('SnapshotId')[0] groups = self.ec2_backend.get_create_volume_permission_groups(snapshot_id) template = self.response_template(DESCRIBE_SNAPSHOT_ATTRIBUTES_RESPONSE) return template.render(snapshot_id=snapshot_id, groups=groups) def modify_snapshot_attribute(self): snapshot_id = self.querystring.get('SnapshotId')[0] operation_type = self.querystring.get('OperationType')[0] group = self.querystring.get('UserGroup.1', [None])[0] user_id = self.querystring.get('UserId.1', [None])[0] if (operation_type == 'add'): self.ec2_backend.add_create_volume_permission(snapshot_id, user_id=user_id, group=group) elif (operation_type == 'remove'): self.ec2_backend.remove_create_volume_permission(snapshot_id, user_id=user_id, group=group) return MODIFY_SNAPSHOT_ATTRIBUTE_RESPONSE def modify_volume_attribute(self): raise NotImplementedError('ElasticBlockStore.modify_volume_attribute is not yet implemented') def reset_snapshot_attribute(self): raise NotImplementedError('ElasticBlockStore.reset_snapshot_attribute is not yet implemented') CREATE_VOLUME_RESPONSE = """ 59dbff89-35bd-4eac-99ed-be587EXAMPLE {{ volume.id }} {{ volume.size }} {% if volume.snapshot_id %} {{ volume.snapshot_id }} {% else %} {% endif %} {{ volume.encrypted }} {{ volume.zone.name }} creating {{ volume.create_time}} standard """ DESCRIBE_VOLUMES_RESPONSE = """ 59dbff89-35bd-4eac-99ed-be587EXAMPLE {% for volume in volumes %} {{ volume.id }} {{ volume.size }} {% if volume.snapshot_id %} {{ volume.snapshot_id }} {% else %} {% endif %} {{ volume.encrypted }} {{ volume.zone.name }} {{ volume.status }} {{ volume.create_time}} {% if volume.attachment %} {{ volume.id }} {{ volume.attachment.instance.id }} {{ volume.attachment.device }} attached {{volume.attachment.attach_time}} false {% endif %} {% for tag in volume.get_tags() %} {{ tag.resource_id }} {{ tag.resource_type }} {{ tag.key }} {{ tag.value }} {% endfor %} standard {% endfor %} """ DELETE_VOLUME_RESPONSE = """ 59dbff89-35bd-4eac-99ed-be587EXAMPLE true """ ATTACHED_VOLUME_RESPONSE = """ 59dbff89-35bd-4eac-99ed-be587EXAMPLE {{ attachment.volume.id }} {{ attachment.instance.id }} {{ attachment.device }} attaching {{attachment.attach_time}} """ DETATCH_VOLUME_RESPONSE = """ 59dbff89-35bd-4eac-99ed-be587EXAMPLE {{ attachment.volume.id }} {{ attachment.instance.id }} {{ attachment.device }} detaching 2013-10-04T17:38:53.000Z """ CREATE_SNAPSHOT_RESPONSE = """ 59dbff89-35bd-4eac-99ed-be587EXAMPLE {{ snapshot.id }} {{ snapshot.volume.id }} pending {{ snapshot.start_time}} 60% 111122223333 {{ snapshot.volume.size }} {{ snapshot.description }} """ DESCRIBE_SNAPSHOTS_RESPONSE = """ 59dbff89-35bd-4eac-99ed-be587EXAMPLE {% for snapshot in snapshots %} {{ snapshot.id }} {{ snapshot.volume.id }} {{ snapshot.status }} {{ snapshot.start_time}} 100% 111122223333 {{ snapshot.volume.size }} {{ snapshot.description }} {% for tag in snapshot.get_tags() %} {{ tag.resource_id }} {{ tag.resource_type }} {{ tag.key }} {{ tag.value }} {% endfor %} {% endfor %} """ DELETE_SNAPSHOT_RESPONSE = """ 59dbff89-35bd-4eac-99ed-be587EXAMPLE true """ DESCRIBE_SNAPSHOT_ATTRIBUTES_RESPONSE = """ a9540c9f-161a-45d8-9cc1-1182b89ad69f snap-a0332ee0 {% if not groups %} {% endif %} {% if groups %} {% for group in groups %} {{ group }} {% endfor %} {% endif %} """ MODIFY_SNAPSHOT_ATTRIBUTE_RESPONSE = """ 666d2944-9276-4d6a-be12-1f4ada972fd8 true """