diff options
| author | Eoghan Glynn <eglynn@redhat.com> | 2012-07-09 11:59:56 +0000 |
|---|---|---|
| committer | Eoghan Glynn <eglynn@redhat.com> | 2012-07-17 18:29:16 +0100 |
| commit | 8600394ec4dd4f800d774e4ed0c24fe087d8e1d3 (patch) | |
| tree | 5d300e4f3bcae57b3c3ced49314b214ecab1dcd5 /nova/api | |
| parent | 500ee77121512fd40f5c2afb885fdc45fbf4b57f (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.py | 44 |
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): |
