add most of the snapshot implementation
This commit is contained in:
parent
f92a3ec00f
commit
e261b82f29
@ -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
|
||||
|
@ -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>"""
|
||||
|
@ -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():
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user