summaryrefslogtreecommitdiffstats
path: root/nova/api
diff options
context:
space:
mode:
authorEoghan Glynn <eglynn@redhat.com>2012-07-09 11:59:56 +0000
committerEoghan Glynn <eglynn@redhat.com>2012-07-17 18:29:16 +0100
commit8600394ec4dd4f800d774e4ed0c24fe087d8e1d3 (patch)
tree5d300e4f3bcae57b3c3ced49314b214ecab1dcd5 /nova/api
parent500ee77121512fd40f5c2afb885fdc45fbf4b57f (diff)
Support EC2 CreateImage API for boot-from-volume
Fixes bug lp 988335 For fidelity with AWS, where the EC2 CreateImage API is only supported for EBS-backed instances, we now support this API for booted-from-volume nova servers. We create a "place-holder" image in glance with the image data being effectively empty, and the following properties set: * the imaged instance's kernel and ramdisk IDs * block device mapping containing the appropriate snapshot ID(s) so that we can boot from this image without providing additional context (such as via the nova boot --block-device-mapping option) Change-Id: I0b3d18d7922f2ad1bc687fa88e2f5d4cf5aa068b
Diffstat (limited to 'nova/api')
-rw-r--r--nova/api/ec2/cloud.py44
1 files changed, 35 insertions, 9 deletions
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index 94302383c..af74e75b8 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -1449,6 +1449,7 @@ class CloudController(object):
# NOTE(yamahata): name/description are ignored by register_image(),
# do so here
no_reboot = kwargs.get('no_reboot', False)
+ name = kwargs.get('name')
validate_ec2_id(instance_id)
ec2_instance_id = instance_id
instance_id = ec2utils.ec2_id_to_id(ec2_instance_id)
@@ -1481,14 +1482,22 @@ class CloudController(object):
raise exception.EC2APIError(
_('Couldn\'t stop instance with in %d sec') % timeout)
- src_image = self._get_image(context, instance['image_ref'])
- properties = src_image['properties']
+ glance_uuid = instance['image_ref']
+ ec2_image_id = ec2utils.glance_id_to_ec2_id(context, glance_uuid)
+ src_image = self._get_image(context, ec2_image_id)
+ new_image = dict(src_image)
+ properties = new_image['properties']
if instance['root_device_name']:
properties['root_device_name'] = instance['root_device_name']
+ # meaningful image name
+ name_map = dict(instance=instance['uuid'], now=timeutils.isotime())
+ new_image['name'] = (name or
+ _('image of %(instance)s at %(now)s') % name_map)
+
mapping = []
bdms = db.block_device_mapping_get_all_by_instance(context,
- instance_id)
+ instance['uuid'])
for bdm in bdms:
if bdm.no_device:
continue
@@ -1501,15 +1510,16 @@ class CloudController(object):
m[attr] = val
volume_id = m.get('volume_id')
- if m.get('snapshot_id') and volume_id:
+ snapshot_id = m.get('snapshot_id')
+ if snapshot_id and volume_id:
# create snapshot based on volume_id
volume = self.volume_api.get(context, volume_id)
# NOTE(yamahata): Should we wait for snapshot creation?
# Linux LVM snapshot creation completes in
# short time, it doesn't matter for now.
+ name = _('snapshot for %s') % new_image['name']
snapshot = self.volume_api.create_snapshot_force(
- context, volume, volume['display_name'],
- volume['display_description'])
+ context, volume, name, volume['display_description'])
m['snapshot_id'] = snapshot['id']
del m['volume_id']
@@ -1536,14 +1546,30 @@ class CloudController(object):
properties['block_device_mapping'] = mapping
for attr in ('status', 'location', 'id'):
- src_image.pop(attr, None)
+ new_image.pop(attr, None)
+
+ # the new image is simply a bucket of properties (particularly the
+ # block device mapping, kernel and ramdisk IDs) with no image data,
+ # hence the zero size
+ new_image['size'] = 0
+
+ def _unmap_id_property(properties, name):
+ if properties[name]:
+ properties[name] = ec2utils.id_to_glance_id(context,
+ properties[name])
- image_id = self._register_image(context, src_image)
+ # ensure the ID properties are unmapped back to the glance UUID
+ _unmap_id_property(properties, 'kernel_id')
+ _unmap_id_property(properties, 'ramdisk_id')
+
+ new_image = self.image_service.service.create(context, new_image,
+ data='')
+ ec2_id = ec2utils.glance_id_to_ec2_id(context, new_image['id'])
if restart_instance:
self.compute_api.start(context, instance_id=instance_id)
- return {'imageId': image_id}
+ return {'imageId': ec2_id}
class CloudSecurityGroupAPI(compute.api.SecurityGroupAPI):