Skip to content

Commit

Permalink
Refactor glance id<->internal id conversion for s3
Browse files Browse the repository at this point in the history
 * Moves nova.image.s3.S3ImageService functions for converting
   between glance ('image_uuid') and internal (db) ids to ec2utils:

       get_image_id => ec2utils.glance_id_to_id
       get_image_uuid => ec2utils.id_to_glance_id

 * Refactors ec2utils.glance_id_to_id to create a new S3Image
   object associating a glance id to an internal id if such a
   mapping does not already exist.  Previously, only calls to
   nova.api.ec2.cloud.CloudController.describe_images would
   add new mappings, but now any attempt to convert a glance id
   to an internal id will succeed, resolving bug 948286.

 * Adds 2 convenience methods to ec2utils, as per bcwaldon:

       ec2_id_to_glance_id
       glance_id_to_ec2_id

 * Since this is a strict refactor and only streamlines existing
   well-tested functionality, this change includes no new tests.

Change-Id: I810afe05223228df1bcc20a0ac688d8c62c472b4
  • Loading branch information
Maru Newby authored and bcwaldon committed Mar 13, 2012
1 parent 094985e commit 0929e3a
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 48 deletions.
28 changes: 9 additions & 19 deletions nova/api/ec2/cloud.py
Expand Up @@ -967,15 +967,14 @@ def _format_kernel_id(self, context, instance_ref, result, key):
kernel_uuid = instance_ref['kernel_id']
if kernel_uuid is None or kernel_uuid == '':
return
kernel_id = self._get_image_id(context, kernel_uuid)
result[key] = ec2utils.image_ec2_id(kernel_id, 'aki')
result[key] = ec2utils.glance_id_to_ec2_id(context, kernel_uuid, 'aki')

def _format_ramdisk_id(self, context, instance_ref, result, key):
ramdisk_uuid = instance_ref['ramdisk_id']
if ramdisk_uuid is None or ramdisk_uuid == '':
return
ramdisk_id = self._get_image_id(context, ramdisk_uuid)
result[key] = ec2utils.image_ec2_id(ramdisk_id, 'ari')
result[key] = ec2utils.glance_id_to_ec2_id(context, ramdisk_uuid,
'ari')

def describe_instance_attribute(self, context, instance_id, attribute,
**kwargs):
Expand Down Expand Up @@ -1173,8 +1172,7 @@ def _format_instances(self, context, instance_id=None, use_v6=False,
ec2_id = ec2utils.id_to_ec2_id(instance_id)
i['instanceId'] = ec2_id
image_uuid = instance['image_ref']
image_id = self._get_image_id(context, image_uuid)
i['imageId'] = ec2utils.image_ec2_id(image_id)
i['imageId'] = ec2utils.glance_id_to_ec2_id(context, image_uuid)
self._format_kernel_id(context, instance, i, 'kernelId')
self._format_ramdisk_id(context, instance, i, 'ramdiskId')
i['instanceState'] = _state_description(
Expand Down Expand Up @@ -1287,16 +1285,17 @@ def run_instances(self, context, **kwargs):
max_count = int(kwargs.get('max_count', 1))
if kwargs.get('kernel_id'):
kernel = self._get_image(context, kwargs['kernel_id'])
kwargs['kernel_id'] = self._get_image_uuid(context, kernel['id'])
kwargs['kernel_id'] = ec2utils.id_to_glance_id(context,
kernel['id'])
if kwargs.get('ramdisk_id'):
ramdisk = self._get_image(context, kwargs['ramdisk_id'])
kwargs['ramdisk_id'] = self._get_image_uuid(context,
ramdisk['id'])
kwargs['ramdisk_id'] = ec2utils.id_to_glance_id(context,
ramdisk['id'])
for bdm in kwargs.get('block_device_mapping', []):
_parse_block_device_mapping(bdm)

image = self._get_image(context, kwargs['image_id'])
image_uuid = self._get_image_uuid(context, image['id'])
image_uuid = ec2utils.id_to_glance_id(context, image['id'])

if image:
image_state = self._get_image_state(image)
Expand Down Expand Up @@ -1383,15 +1382,6 @@ def _get_image(self, context, ec2_id):
raise exception.ImageNotFound(image_id=ec2_id)
return image

# NOTE(bcwaldon): We need access to the image uuid since we directly
# call the compute api from this class
def _get_image_uuid(self, context, internal_id):
return self.image_service.get_image_uuid(context, internal_id)

# NOTE(bcwaldon): We also need to be able to map image uuids to integers
def _get_image_id(self, context, image_uuid):
return self.image_service.get_image_id(context, image_uuid)

def _format_image(self, image):
"""Convert from format defined by GlanceImageService to S3 format."""
i = {}
Expand Down
26 changes: 26 additions & 0 deletions nova/api/ec2/ec2utils.py
Expand Up @@ -18,6 +18,7 @@

import re

from nova import db
from nova import exception
from nova import flags
from nova import log as logging
Expand Down Expand Up @@ -46,6 +47,31 @@ def image_type(image_type):
return image_type


def id_to_glance_id(context, image_id):
"""Convert an internal (db) id to a glance id."""
return db.s3_image_get(context, image_id)['uuid']


def glance_id_to_id(context, glance_id):
"""Convert a glance id to an internal (db) id."""
if glance_id is None:
return
try:
return db.s3_image_get_by_uuid(context, glance_id)['id']
except exception.NotFound:
return db.s3_image_create(context, glance_id)['id']


def ec2_id_to_glance_id(context, ec2_id):
image_id = ec2_id_to_id(ec2_id)
return id_to_glance_id(context, image_id)


def glance_id_to_ec2_id(context, glance_id, image_type='ami'):
image_id = glance_id_to_id(context, glance_id)
return image_ec2_id(image_id, image_type=image_type)


def ec2_id_to_id(ec2_id):
"""Convert an ec2 ID (i-[base 16 number]) to an instance id (int)"""
try:
Expand Down
40 changes: 11 additions & 29 deletions nova/image/s3.py
Expand Up @@ -30,7 +30,6 @@
import eventlet

from nova import rpc
import nova.db.api
from nova import exception
from nova import flags
from nova import image
Expand Down Expand Up @@ -65,43 +64,27 @@ def __init__(self, service=None, *args, **kwargs):
self.service = service or image.get_default_image_service()
self.service.__init__(*args, **kwargs)

def get_image_uuid(self, context, image_id):
return nova.db.api.s3_image_get(context, image_id)['uuid']

def get_image_id(self, context, image_uuid):
return nova.db.api.s3_image_get_by_uuid(context, image_uuid)['id']

def _create_image_id(self, context, image_uuid):
return nova.db.api.s3_image_create(context, image_uuid)['id']

def _translate_uuids_to_ids(self, context, images):
return [self._translate_uuid_to_id(context, img) for img in images]

def _translate_uuid_to_id(self, context, image):
def _find_or_create(image_uuid):
if image_uuid is None:
return
try:
return self.get_image_id(context, image_uuid)
except exception.NotFound:
return self._create_image_id(context, image_uuid)

image_copy = image.copy()

try:
image_id = image_copy['id']
image_uuid = image_copy['id']
except KeyError:
pass
else:
image_copy['id'] = _find_or_create(image_id)
image_copy['id'] = ec2utils.glance_id_to_id(context, image_uuid)

for prop in ['kernel_id', 'ramdisk_id']:
try:
image_uuid = image_copy['properties'][prop]
except (KeyError, ValueError):
pass
else:
image_copy['properties'][prop] = _find_or_create(image_uuid)
image_id = ec2utils.glance_id_to_id(context, image_uuid)
image_copy['properties'][prop] = image_id

return image_copy

Expand All @@ -113,15 +96,15 @@ def _translate_id_to_uuid(self, context, image):
except KeyError:
pass
else:
image_copy['id'] = self.get_image_uuid(context, image_id)
image_copy['id'] = ec2utils.id_to_glance_id(context, image_id)

for prop in ['kernel_id', 'ramdisk_id']:
try:
image_id = image_copy['properties'][prop]
except (KeyError, ValueError):
pass
else:
image_uuid = self.get_image_uuid(context, image_id)
image_uuid = ec2utils.id_to_glance_id(context, image_id)
image_copy['properties'][prop] = image_uuid

return image_copy
Expand All @@ -136,11 +119,11 @@ def create(self, context, metadata, data=None):
return image

def delete(self, context, image_id):
image_uuid = self.get_image_uuid(context, image_id)
image_uuid = ec2utils.id_to_glance_id(context, image_id)
self.service.delete(context, image_uuid)

def update(self, context, image_id, metadata, data=None):
image_uuid = self.get_image_uuid(context, image_id)
image_uuid = ec2utils.id_to_glance_id(context, image_id)
metadata = self._translate_id_to_uuid(context, metadata)
image = self.service.update(context, image_uuid, metadata, data)
return self._translate_uuid_to_id(context, image)
Expand All @@ -158,7 +141,7 @@ def detail(self, context):
return self._translate_uuids_to_ids(context, images)

def show(self, context, image_id):
image_uuid = self.get_image_uuid(context, image_id)
image_uuid = ec2utils.id_to_glance_id(context, image_id)
image = self.service.show(context, image_uuid)
return self._translate_uuid_to_id(context, image)

Expand Down Expand Up @@ -241,8 +224,7 @@ def _s3_parse_manifest(self, context, metadata, manifest):
properties['architecture'] = arch

def _translate_dependent_image_id(image_key, image_id):
image_id = ec2utils.ec2_id_to_id(image_id)
image_uuid = self.get_image_uuid(context, image_id)
image_uuid = ec2utils.ec2_id_to_glance_id(context, image_id)
properties[image_key] = image_uuid

if kernel_id:
Expand All @@ -269,7 +251,7 @@ def _translate_dependent_image_id(image_key, image_id):

# extract the new uuid and generate an int id to present back to user
image_uuid = image['id']
image['id'] = self._create_image_id(context, image_uuid)
image['id'] = ec2utils.glance_id_to_id(context, image_uuid)

# return image_uuid so the caller can still make use of image_service
return manifest, image, image_uuid
Expand Down

0 comments on commit 0929e3a

Please sign in to comment.