Merge pull request #216 from DreadPirateShawn/ImplementCopyImage
AMI: Implement copy_image.
This commit is contained in:
commit
f0724d458e
@ -593,19 +593,33 @@ class TagBackend(object):
|
||||
|
||||
|
||||
class Ami(TaggedEC2Instance):
|
||||
def __init__(self, ami_id, instance, name, description):
|
||||
def __init__(self, ami_id, instance=None, source_ami=None, name=None, description=None):
|
||||
self.id = ami_id
|
||||
self.state = "available"
|
||||
|
||||
self.instance = instance
|
||||
self.instance_id = instance.id
|
||||
self.virtualization_type = instance.virtualization_type
|
||||
self.architecture = instance.architecture
|
||||
self.kernel_id = instance.kernel
|
||||
self.platform = instance.platform
|
||||
if instance:
|
||||
self.instance = instance
|
||||
self.instance_id = instance.id
|
||||
self.virtualization_type = instance.virtualization_type
|
||||
self.architecture = instance.architecture
|
||||
self.kernel_id = instance.kernel
|
||||
self.platform = instance.platform
|
||||
self.name = name
|
||||
self.description = description
|
||||
|
||||
elif source_ami:
|
||||
"""
|
||||
http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/CopyingAMIs.html
|
||||
"We don't copy launch permissions, user-defined tags, or Amazon S3 bucket permissions from the source AMI to the new AMI."
|
||||
~ 2014.09.29
|
||||
"""
|
||||
self.virtualization_type = source_ami.virtualization_type
|
||||
self.architecture = source_ami.architecture
|
||||
self.kernel_id = source_ami.kernel_id
|
||||
self.platform = source_ami.platform
|
||||
self.name = name if name else source_ami.name
|
||||
self.description = description if description else source_ami.description
|
||||
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.launch_permission_groups = set()
|
||||
|
||||
# AWS auto-creates these, we should reflect the same.
|
||||
@ -637,11 +651,18 @@ class AmiBackend(object):
|
||||
self.amis = {}
|
||||
super(AmiBackend, self).__init__()
|
||||
|
||||
def create_image(self, instance_id, name, description):
|
||||
def create_image(self, instance_id, name=None, description=None):
|
||||
# TODO: check that instance exists and pull info from it.
|
||||
ami_id = random_ami_id()
|
||||
instance = self.get_instance(instance_id)
|
||||
ami = Ami(ami_id, instance, name, description)
|
||||
ami = Ami(ami_id, instance=instance, source_ami=None, name=name, description=description)
|
||||
self.amis[ami_id] = ami
|
||||
return ami
|
||||
|
||||
def copy_image(self, source_image_id, source_region, name=None, description=None):
|
||||
source_ami = ec2_backends[source_region].describe_images(ami_ids=[source_image_id])[0]
|
||||
ami_id = random_ami_id()
|
||||
ami = Ami(ami_id, instance=None, source_ami=source_ami, name=name, description=description)
|
||||
self.amis[ami_id] = ami
|
||||
return ami
|
||||
|
||||
|
@ -19,6 +19,15 @@ class AmisResponse(BaseResponse):
|
||||
template = Template(CREATE_IMAGE_RESPONSE)
|
||||
return template.render(image=image)
|
||||
|
||||
def copy_image(self):
|
||||
source_image_id = self.querystring.get('SourceImageId')[0]
|
||||
source_region = self.querystring.get('SourceRegion')[0]
|
||||
name = self.querystring.get('Name')[0] if self.querystring.get('Name') else None
|
||||
description = self.querystring.get('Description')[0] if self.querystring.get('Description') else None
|
||||
image = ec2_backend.copy_image(source_image_id, source_region, name, description)
|
||||
template = Template(COPY_IMAGE_RESPONSE)
|
||||
return template.render(image=image)
|
||||
|
||||
def deregister_image(self):
|
||||
ami_id = self.querystring.get('ImageId')[0]
|
||||
success = ec2_backend.deregister_image(ami_id)
|
||||
@ -61,6 +70,11 @@ CREATE_IMAGE_RESPONSE = """<CreateImageResponse xmlns="http://ec2.amazonaws.com/
|
||||
<imageId>{{ image.id }}</imageId>
|
||||
</CreateImageResponse>"""
|
||||
|
||||
COPY_IMAGE_RESPONSE = """<CopyImageResponse xmlns="http://ec2.amazonaws.com/doc/2013-07-15/">
|
||||
<requestId>60bc441d-fa2c-494d-b155-5d6a3EXAMPLE</requestId>
|
||||
<imageId>{{ image.id }}</imageId>
|
||||
</CopyImageResponse>"""
|
||||
|
||||
# TODO almost all of these params should actually be templated based on the ec2 image
|
||||
DESCRIBE_IMAGES_RESPONSE = """<DescribeImagesResponse xmlns="http://ec2.amazonaws.com/doc/2012-12-01/">
|
||||
<requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
|
||||
|
@ -9,6 +9,7 @@ from boto.exception import EC2ResponseError
|
||||
import sure # noqa
|
||||
|
||||
from moto import mock_ec2
|
||||
from tests.helpers import requires_boto_gte
|
||||
|
||||
|
||||
@mock_ec2
|
||||
@ -51,6 +52,50 @@ def test_ami_create_and_delete():
|
||||
cm.exception.request_id.should_not.be.none
|
||||
|
||||
|
||||
@requires_boto_gte("2.14.0")
|
||||
@mock_ec2
|
||||
def test_ami_copy():
|
||||
conn = boto.connect_ec2('the_key', 'the_secret')
|
||||
reservation = conn.run_instances('ami-1234abcd')
|
||||
instance = reservation.instances[0]
|
||||
|
||||
source_image_id = conn.create_image(instance.id, "test-ami", "this is a test ami")
|
||||
source_image = conn.get_all_images(image_ids=[source_image_id])[0]
|
||||
|
||||
# Boto returns a 'CopyImage' object with an image_id attribute here. Use the image_id to fetch the full info.
|
||||
copy_image_ref = conn.copy_image(source_image.region.name, source_image.id, "test-copy-ami", "this is a test copy ami")
|
||||
copy_image_id = copy_image_ref.image_id
|
||||
copy_image = conn.get_all_images(image_ids=[copy_image_id])[0]
|
||||
|
||||
copy_image.id.should.equal(copy_image_id)
|
||||
copy_image.virtualization_type.should.equal(source_image.virtualization_type)
|
||||
copy_image.architecture.should.equal(source_image.architecture)
|
||||
copy_image.kernel_id.should.equal(source_image.kernel_id)
|
||||
copy_image.platform.should.equal(source_image.platform)
|
||||
|
||||
# Validate auto-created volume and snapshot
|
||||
conn.get_all_volumes().should.have.length_of(2)
|
||||
conn.get_all_snapshots().should.have.length_of(2)
|
||||
|
||||
copy_image.block_device_mapping.current_value.snapshot_id.should_not.equal(
|
||||
source_image.block_device_mapping.current_value.snapshot_id)
|
||||
|
||||
# Copy from non-existent source ID.
|
||||
with assert_raises(EC2ResponseError) as cm:
|
||||
conn.copy_image(source_image.region.name, 'ami-abcd1234', "test-copy-ami", "this is a test copy ami")
|
||||
cm.exception.code.should.equal('InvalidAMIID.NotFound')
|
||||
cm.exception.status.should.equal(400)
|
||||
cm.exception.request_id.should_not.be.none
|
||||
|
||||
# Copy from non-existent source region.
|
||||
with assert_raises(EC2ResponseError) as cm:
|
||||
invalid_region = 'us-east-1' if (source_image.region.name != 'us-east-1') else 'us-west-1'
|
||||
conn.copy_image(invalid_region, source_image.id, "test-copy-ami", "this is a test copy ami")
|
||||
cm.exception.code.should.equal('InvalidAMIID.NotFound')
|
||||
cm.exception.status.should.equal(400)
|
||||
cm.exception.request_id.should_not.be.none
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_ami_tagging():
|
||||
conn = boto.connect_vpc('the_key', 'the_secret')
|
||||
|
Loading…
Reference in New Issue
Block a user