add most of the snapshot implementation

This commit is contained in:
Steve Pulec 2013-02-23 18:01:41 -05:00
parent f92a3ec00f
commit e261b82f29
4 changed files with 109 additions and 4 deletions

View File

@ -3,7 +3,14 @@ from collections import defaultdict
from boto.ec2.instance import Instance, InstanceState, Reservation
from moto.core import BaseBackend
from .utils import random_instance_id, random_reservation_id, random_ami_id, random_security_group_id, random_volume_id
from .utils import (
random_ami_id,
random_instance_id,
random_reservation_id,
random_security_group_id,
random_snapshot_id,
random_volume_id,
)
class InstanceBackend(object):
@ -306,10 +313,18 @@ class Volume(object):
return 'available'
class Snapshot(object):
def __init__(self, snapshot_id, volume, description):
self.id = snapshot_id
self.volume = volume
self.description = description
class EBSBackend(object):
def __init__(self):
self.volumes = {}
self.attachments = {}
self.snapshots = {}
super(EBSBackend, self).__init__()
def create_volume(self, size, zone_name):
@ -348,6 +363,21 @@ class EBSBackend(object):
volume.attachment = None
return old_attachment
def create_snapshot(self, volume_id, description):
snapshot_id = random_snapshot_id()
volume = self.volumes.get(volume_id)
snapshot = Snapshot(snapshot_id, volume, description)
self.snapshots[snapshot_id] = snapshot
return snapshot
def describe_snapshots(self):
return self.snapshots.values()
def delete_snapshot(self, snapshot_id):
if snapshot_id in self.snapshots:
return self.snapshots.pop(snapshot_id)
return False
class EC2Backend(BaseBackend, InstanceBackend, TagBackend, AmiBackend, RegionsAndZonesBackend, SecurityGroupBackend, EBSBackend):
pass

View File

@ -21,7 +21,13 @@ class ElasticBlockStore(object):
raise NotImplementedError('ElasticBlockStore.copy_snapshot is not yet implemented')
def create_snapshot(self):
raise NotImplementedError('ElasticBlockStore.create_snapshot is not yet implemented')
description = None
if 'Description' in self.querystring:
description = self.querystring.get('Description')[0]
volume_id = self.querystring.get('VolumeId')[0]
snapshot = ec2_backend.create_snapshot(volume_id, description)
template = Template(CREATE_SNAPSHOT_RESPONSE)
return template.render(snapshot=snapshot)
def create_volume(self):
size = self.querystring.get('Size')[0]
@ -31,7 +37,12 @@ class ElasticBlockStore(object):
return template.render(volume=volume)
def delete_snapshot(self):
raise NotImplementedError('ElasticBlockStore.delete_snapshot is not yet implemented')
snapshot_id = self.querystring.get('SnapshotId')[0]
success = ec2_backend.delete_snapshot(snapshot_id)
if not success:
# Snapshot doesn't exist
return "Snapshot with id {} does not exist".format(snapshot_id), dict(status=404)
return DELETE_SNAPSHOT_RESPONSE
def delete_volume(self):
volume_id = self.querystring.get('VolumeId')[0]
@ -45,7 +56,9 @@ class ElasticBlockStore(object):
raise NotImplementedError('ElasticBlockStore.describe_snapshot_attribute is not yet implemented')
def describe_snapshots(self):
raise NotImplementedError('ElasticBlockStore.describe_snapshots is not yet implemented')
snapshots = ec2_backend.describe_snapshots()
template = Template(DESCRIBE_SNAPSHOTS_RESPONSE)
return template.render(snapshots=snapshots)
def describe_volumes(self):
volumes = ec2_backend.describe_volumes()
@ -150,3 +163,39 @@ DETATCH_VOLUME_RESPONSE = """<DetachVolumeResponse xmlns="http://ec2.amazonaws.c
<attachTime>YYYY-MM-DDTHH:MM:SS.000Z</attachTime>
</DetachVolumeResponse>"""
CREATE_SNAPSHOT_RESPONSE = """<CreateSnapshotResponse xmlns="http://ec2.amazonaws.com/doc/2012-12-01/">
<requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
<snapshotId>{{ snapshot.id }}</snapshotId>
<volumeId>{{ snapshot.volume.id }}</volumeId>
<status>pending</status>
<startTime>YYYY-MM-DDTHH:MM:SS.000Z</startTime>
<progress>60%</progress>
<ownerId>111122223333</ownerId>
<volumeSize>{{ snapshot.volume.size }}</volumeSize>
<description>{{ snapshot.description }}</description>
</CreateSnapshotResponse>"""
DESCRIBE_SNAPSHOTS_RESPONSE = """<DescribeSnapshotsResponse xmlns="http://ec2.amazonaws.com/doc/2012-12-01/">
<requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
<snapshotSet>
{% for snapshot in snapshots %}
<item>
<snapshotId>{{ snapshot.id }}</snapshotId>
<volumeId>{{ snapshot.volume.id }}</volumeId>
<status>pending</status>
<startTime>YYYY-MM-DDTHH:MM:SS.SSSZ</startTime>
<progress>30%</progress>
<ownerId>111122223333</ownerId>
<volumeSize>{{ snapshot.volume.size }}</volumeSize>
<description>{{ snapshot.description }}</description>
<tagSet>
</tagSet>
</item>
{% endfor %}
</snapshotSet>
</DescribeSnapshotsResponse>"""
DELETE_SNAPSHOT_RESPONSE = """<DeleteSnapshotResponse xmlns="http://ec2.amazonaws.com/doc/2012-12-01/">
<requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
<return>true</return>
</DeleteSnapshotResponse>"""

View File

@ -30,6 +30,10 @@ def random_volume_id():
return random_id(prefix='vol')
def random_snapshot_id():
return random_id(prefix='snap')
def instance_ids_from_querystring(querystring_dict):
instance_ids = []
for key, value in querystring_dict.iteritems():

View File

@ -48,3 +48,25 @@ def test_volume_attach_and_detach():
volume.volume_state().should.equal('available')
conn.detach_volume.when.called_with(volume.id, instance.id, "/dev/sdh").should.throw(EC2ResponseError)
@mock_ec2
def test_create_snapshot():
conn = boto.connect_ec2('the_key', 'the_secret')
volume = conn.create_volume(80, "us-east-1a")
volume.create_snapshot('a test snapshot')
snapshots = conn.get_all_snapshots()
snapshots.should.have.length_of(1)
snapshots[0].description.should.equal('a test snapshot')
# Create snapshot without description
snapshot = volume.create_snapshot()
conn.get_all_snapshots().should.have.length_of(2)
snapshot.delete()
conn.get_all_snapshots().should.have.length_of(1)
# Deleting something that was already deleted should throw an error
snapshot.delete.when.called_with().should.throw(EC2ResponseError)