Reducing the number of compute calls to Glance

Fixes bug 886224

Change-Id: Ibd270d24eb68cc2503fee933a2154125995d352d
This commit is contained in:
Brian Waldon 2011-11-04 12:44:30 -04:00
parent 93c0240875
commit cb05f783d0
13 changed files with 86 additions and 61 deletions

View File

@ -127,6 +127,11 @@ def checks_instance_lock(function):
return decorated_function
def _get_image_meta(context, image_ref):
image_service, image_id = nova.image.get_image_service(context, image_ref)
return image_service.show(context, image_id)
class ComputeManager(manager.SchedulerDependentManager):
"""Manages the running instances from creation to destruction."""
@ -310,7 +315,7 @@ class ComputeManager(manager.SchedulerDependentManager):
def _run_instance(self, context, instance_id, **kwargs):
"""Launch a new instance with specified options."""
def _check_image_size():
def _check_image_size(image_meta):
"""Ensure image is smaller than the maximum size allowed by the
instance_type.
@ -325,13 +330,6 @@ class ComputeManager(manager.SchedulerDependentManager):
image, but is accurate because it reflects the image's
actual size.
"""
# NOTE(jk0): image_ref is defined in the DB model, image_href is
# used by the image service. This should be refactored to be
# consistent.
image_href = instance['image_ref']
image_service, image_id = nova.image.get_image_service(context,
image_href)
image_meta = image_service.show(context, image_id)
try:
size_bytes = image_meta['size']
@ -355,6 +353,7 @@ class ComputeManager(manager.SchedulerDependentManager):
allowed_size_bytes = allowed_size_gb * 1024 * 1024 * 1024
image_id = image_meta['id']
LOG.debug(_("image_id=%(image_id)s, image_size_bytes="
"%(size_bytes)d, allowed_size_bytes="
"%(allowed_size_bytes)d") % locals())
@ -427,7 +426,9 @@ class ComputeManager(manager.SchedulerDependentManager):
if instance['name'] in self.driver.list_instances():
raise exception.Error(_("Instance has already been created"))
_check_image_size()
image_meta = _get_image_meta(context, instance['image_ref'])
_check_image_size(image_meta)
LOG.audit(_("instance %s: starting..."), instance_id,
context=context)
@ -460,7 +461,7 @@ class ComputeManager(manager.SchedulerDependentManager):
# TODO(vish) check to make sure the availability zone matches
with _logging_error(instance_id, "failed to spawn"):
self.driver.spawn(context, instance,
self.driver.spawn(context, instance, image_meta,
network_info, block_device_info)
current_power_state = self._get_power_state(context, instance)
@ -664,7 +665,10 @@ class ComputeManager(manager.SchedulerDependentManager):
instance_ref.admin_pass = kwargs.get('new_pass',
utils.generate_password(FLAGS.password_length))
self.driver.spawn(context, instance_ref, network_info, bd_mapping)
image_meta = _get_image_meta(context, instance_ref['image_ref'])
self.driver.spawn(context, instance_ref, image_meta,
network_info, bd_mapping)
current_power_state = self._get_power_state(context, instance_ref)
self._instance_update(context,
@ -1146,8 +1150,13 @@ class ComputeManager(manager.SchedulerDependentManager):
instance_ref.uuid)
network_info = self._get_instance_nw_info(context, instance_ref)
# Have to look up image here since we depend on disk_format later
image_meta = _get_image_meta(context, instance_ref['image_ref'])
self.driver.finish_migration(context, migration_ref, instance_ref,
disk_info, network_info, resize_instance)
disk_info, network_info, image_meta,
resize_instance)
self._instance_update(context,
instance_id,

View File

@ -14,6 +14,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
import StringIO
from nova import exception
@ -74,11 +75,15 @@ class FakeGlance(object):
pass
def get_image_meta(self, image_id):
return self.IMAGE_FIXTURES[int(image_id)]['image_meta']
meta = copy.deepcopy(self.IMAGE_FIXTURES[int(image_id)]['image_meta'])
meta['id'] = image_id
return meta
def get_image(self, image_id):
image = self.IMAGE_FIXTURES[int(image_id)]
return image['image_meta'], image['image_data']
meta = copy.deepcopy(image['image_meta'])
meta['id'] = image_id
return meta, image['image_data']
NOW_GLANCE_FORMAT = "2010-10-11T10:30:22"

View File

@ -74,6 +74,12 @@ class VMWareAPIVMTestCase(test.TestCase):
'mac': 'DE:AD:BE:EF:00:00',
'rxtx_cap': 3})]
self.image = {
'id': 'c1c8ce3d-c2e0-4247-890c-ccf5cc1c004c',
'disk_format': 'vhd',
'size': 512,
}
def tearDown(self):
super(VMWareAPIVMTestCase, self).tearDown()
vmwareapi_fake.cleanup()
@ -95,7 +101,8 @@ class VMWareAPIVMTestCase(test.TestCase):
"""Create and spawn the VM."""
self._create_instance_in_the_db()
self.type_data = db.instance_type_get_by_name(None, 'm1.large')
self.conn.spawn(self.context, self.instance, self.network_info)
self.conn.spawn(self.context, self.instance, self.image,
self.network_info)
self._check_vm_record()
def _check_vm_record(self):

View File

@ -423,7 +423,9 @@ class XenAPIVMTestCase(test.TestCase):
if empty_dns:
network_info[0][1]['dns'] = []
self.conn.spawn(self.context, instance, network_info)
image_meta = {'id': glance_stubs.FakeGlance.IMAGE_VHD,
'disk_format': 'vhd'}
self.conn.spawn(self.context, instance, image_meta, network_info)
self.create_vm_record(self.conn, os_type, instance_id)
self.check_vm_record(self.conn, check_injection)
self.assertTrue(instance.os_type)
@ -694,8 +696,10 @@ class XenAPIVMTestCase(test.TestCase):
'label': 'fake',
'mac': 'DE:AD:BE:EF:00:00',
'rxtx_cap': 3})]
image_meta = {'id': glance_stubs.FakeGlance.IMAGE_VHD,
'disk_format': 'vhd'}
if spawn:
self.conn.spawn(self.context, instance, network_info)
self.conn.spawn(self.context, instance, image_meta, network_info)
return instance
@ -842,9 +846,10 @@ class XenAPIMigrateInstance(test.TestCase):
'label': 'fake',
'mac': 'DE:AD:BE:EF:00:00',
'rxtx_cap': 3})]
image_meta = {'id': instance.image_ref, 'disk_format': 'vhd'}
conn.finish_migration(self.context, self.migration, instance,
dict(base_copy='hurr', cow='durr'),
network_info, resize_instance=True)
network_info, image_meta, resize_instance=True)
self.assertEqual(self.called, True)
self.assertEqual(self.fake_vm_start_called, True)
@ -883,9 +888,10 @@ class XenAPIMigrateInstance(test.TestCase):
'label': 'fake',
'mac': 'DE:AD:BE:EF:00:00',
'rxtx_cap': 3})]
image_meta = {'id': instance.image_ref, 'disk_format': 'vhd'}
conn.finish_migration(self.context, self.migration, instance,
dict(base_copy='hurr', cow='durr'),
network_info, resize_instance=True)
network_info, image_meta, resize_instance=True)
self.assertEqual(self.called, True)
self.assertEqual(self.fake_vm_start_called, True)
@ -918,9 +924,10 @@ class XenAPIMigrateInstance(test.TestCase):
'label': 'fake',
'mac': 'DE:AD:BE:EF:00:00',
'rxtx_cap': 3})]
image_meta = {'id': instance.image_ref, 'disk_format': 'vhd'}
conn.finish_migration(self.context, self.migration, instance,
dict(base_copy='hurr', cow='durr'),
network_info, resize_instance=True)
network_info, image_meta, resize_instance=True)
def test_finish_migrate_no_resize_vdi(self):
instance = db.instance_create(self.context, self.instance_values)
@ -949,9 +956,10 @@ class XenAPIMigrateInstance(test.TestCase):
'rxtx_cap': 3})]
# Resize instance would be determined by the compute call
image_meta = {'id': instance.image_ref, 'disk_format': 'vhd'}
conn.finish_migration(self.context, self.migration, instance,
dict(base_copy='hurr', cow='durr'),
network_info, resize_instance=False)
network_info, image_meta, resize_instance=False)
class XenAPIImageTypeTestCase(test.TestCase):
@ -986,8 +994,9 @@ class XenAPIDetermineDiskImageTestCase(test.TestCase):
def assert_disk_type(self, disk_type):
ctx = context.RequestContext('fake', 'fake')
dt = vm_utils.VMHelper.determine_disk_image_type(
self.fake_instance, ctx)
fake_glance = glance_stubs.FakeGlance('')
image_meta = fake_glance.get_image_meta(self.fake_instance.image_ref)
dt = vm_utils.VMHelper.determine_disk_image_type(image_meta)
self.assertEqual(disk_type, dt)
def test_instance_disk(self):

View File

@ -127,7 +127,7 @@ class ComputeDriver(object):
# TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def spawn(self, context, instance,
def spawn(self, context, instance, image_meta,
network_info=None, block_device_info=None):
"""
Create a new instance/VM/domain on the virtualization platform.
@ -143,6 +143,8 @@ class ComputeDriver(object):
:param instance: Instance object as returned by DB layer.
This function should use the data there to guide
the creation of the new instance.
:param image_meta: image object returned by nova.image.glance that
defines the image from which to boot this instance
:param network_info:
:py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
:param block_device_info: Information about block devices to be
@ -253,11 +255,14 @@ class ComputeDriver(object):
raise NotImplementedError()
def finish_migration(self, context, migration, instance, disk_info,
network_info, resize_instance):
network_info, image_meta, resize_instance):
"""Completes a resize, turning on the migrated instance
:param network_info:
:py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
:param image_meta: image object returned by nova.image.glance that
defines the image from which this instance
was created
"""
raise NotImplementedError()

View File

@ -97,7 +97,7 @@ class FakeConnection(driver.ComputeDriver):
"""Plugin VIFs into networks."""
pass
def spawn(self, context, instance,
def spawn(self, context, instance, image_meta,
network_info=None, block_device_info=None):
name = instance.name
state = power_state.RUNNING

View File

@ -138,7 +138,7 @@ class HyperVConnection(driver.ComputeDriver):
return instance_infos
def spawn(self, context, instance,
def spawn(self, context, instance, image_meta,
network_info=None, block_device_info=None):
""" Create a new VM and start it."""
vm = self._lookup(instance.name)

View File

@ -641,7 +641,7 @@ class LibvirtConnection(driver.ComputeDriver):
# NOTE(ilyaalekseyev): Implementation like in multinics
# for xenapi(tr3buchet)
@exception.wrap_exception()
def spawn(self, context, instance, network_info,
def spawn(self, context, instance, image_meta, network_info,
block_device_info=None):
xml = self.to_xml(instance, network_info, False,
block_device_info=block_device_info)

View File

@ -79,7 +79,7 @@ class VMWareVMOps(object):
LOG.debug(_("Got total of %s instances") % str(len(lst_vm_names)))
return lst_vm_names
def spawn(self, context, instance, network_info):
def spawn(self, context, instance, image_meta, network_info):
"""
Creates a VM instance.

View File

@ -124,10 +124,10 @@ class VMWareESXConnection(driver.ComputeDriver):
"""List VM instances."""
return self._vmops.list_instances()
def spawn(self, context, instance, network_info,
def spawn(self, context, instance, image_meta, network_info,
block_device_mapping=None):
"""Create VM instance."""
self._vmops.spawn(context, instance, network_info)
self._vmops.spawn(context, instance, image_meta, network_info)
def snapshot(self, context, instance, name):
"""Create snapshot from a running VM instance."""

View File

@ -717,7 +717,7 @@ w
raise e
@classmethod
def determine_disk_image_type(cls, instance, context):
def determine_disk_image_type(cls, image_meta):
"""Disk Image Types are used to determine where the kernel will reside
within an image. To figure out which type we're dealing with, we use
the following rules:
@ -736,12 +736,11 @@ w
ImageType.DISK_VHD: 'DISK_VHD',
ImageType.DISK_ISO: 'DISK_ISO'}
disk_format = pretty_format[image_type]
image_ref = instance.image_ref
instance_id = instance.id
image_ref = image_meta['id']
LOG.debug(_("Detected %(disk_format)s format for image "
"%(image_ref)s, instance %(instance_id)s") % locals())
"%(image_ref)s") % locals())
def determine_from_glance():
def determine_from_image_meta():
glance_disk_format2nova_type = {
'ami': ImageType.DISK,
'aki': ImageType.KERNEL,
@ -749,23 +748,13 @@ w
'raw': ImageType.DISK_RAW,
'vhd': ImageType.DISK_VHD,
'iso': ImageType.DISK_ISO}
image_ref = instance.image_ref
glance_client, image_id = glance.get_glance_client(context,
image_ref)
meta = glance_client.get_image_meta(image_id)
disk_format = meta['disk_format']
disk_format = image_meta['disk_format']
try:
return glance_disk_format2nova_type[disk_format]
except KeyError:
raise exception.InvalidDiskFormat(disk_format=disk_format)
def determine_from_instance():
if instance.kernel_id:
return ImageType.DISK
else:
return ImageType.DISK_RAW
image_type = determine_from_glance()
image_type = determine_from_image_meta()
log_disk_format(image_type)
return image_type

View File

@ -139,13 +139,13 @@ class VMOps(object):
self._start(instance, vm_ref)
def finish_migration(self, context, migration, instance, disk_info,
network_info, resize_instance):
network_info, image_meta, resize_instance):
vdi_uuid = self.link_disks(instance, disk_info['base_copy'],
disk_info['cow'])
vm_ref = self._create_vm(context, instance,
[dict(vdi_type='os', vdi_uuid=vdi_uuid)],
network_info)
network_info, image_meta)
if resize_instance:
self.resize_instance(instance, vdi_uuid)
@ -165,8 +165,8 @@ class VMOps(object):
LOG.debug(_("Starting instance %s"), instance.name)
self._session.call_xenapi('VM.start', vm_ref, False, False)
def _create_disks(self, context, instance):
disk_image_type = VMHelper.determine_disk_image_type(instance, context)
def _create_disks(self, context, instance, image_meta):
disk_image_type = VMHelper.determine_disk_image_type(image_meta)
vdis = VMHelper.fetch_image(context, self._session,
instance, instance.image_ref,
instance.user_id, instance.project_id,
@ -178,7 +178,7 @@ class VMOps(object):
return vdis
def spawn(self, context, instance, network_info):
def spawn(self, context, instance, image_meta, network_info):
vdis = None
try:
# 1. Vanity Step
@ -193,13 +193,14 @@ class VMOps(object):
total_steps=BUILD_TOTAL_STEPS)
# 2. Fetch the Image over the Network
vdis = self._create_disks(context, instance)
vdis = self._create_disks(context, instance, image_meta)
self._update_instance_progress(context, instance,
step=2,
total_steps=BUILD_TOTAL_STEPS)
# 3. Create the VM records
vm_ref = self._create_vm(context, instance, vdis, network_info)
vm_ref = self._create_vm(context, instance, vdis, network_info,
image_meta)
self._update_instance_progress(context, instance,
step=3,
total_steps=BUILD_TOTAL_STEPS)
@ -222,7 +223,7 @@ class VMOps(object):
"""Spawn a rescue instance."""
self.spawn(context, instance, network_info)
def _create_vm(self, context, instance, vdis, network_info):
def _create_vm(self, context, instance, vdis, network_info, image_meta):
"""Create VM instance."""
instance_name = instance.name
vm_ref = VMHelper.lookup(self._session, instance_name)
@ -233,7 +234,7 @@ class VMOps(object):
if not VMHelper.ensure_free_mem(self._session, instance):
raise exception.InsufficientFreeMemory(uuid=instance.uuid)
disk_image_type = VMHelper.determine_disk_image_type(instance, context)
disk_image_type = VMHelper.determine_disk_image_type(image_meta)
kernel = None
ramdisk = None
try:

View File

@ -193,10 +193,10 @@ class XenAPIConnection(driver.ComputeDriver):
def list_instances_detail(self):
return self._vmops.list_instances_detail()
def spawn(self, context, instance,
def spawn(self, context, instance, image_meta,
network_info=None, block_device_info=None):
"""Create VM instance"""
self._vmops.spawn(context, instance, network_info)
self._vmops.spawn(context, instance, image_meta, network_info)
def confirm_migration(self, migration, instance, network_info):
"""Confirms a resize, destroying the source VM"""
@ -208,10 +208,10 @@ class XenAPIConnection(driver.ComputeDriver):
self._vmops.finish_revert_migration(instance)
def finish_migration(self, context, migration, instance, disk_info,
network_info, resize_instance=False):
network_info, image_meta, resize_instance=False):
"""Completes a resize, turning on the migrated instance"""
self._vmops.finish_migration(context, migration, instance, disk_info,
network_info, resize_instance)
network_info, image_meta, resize_instance)
def snapshot(self, context, instance, image_id):
""" Create snapshot from a running VM instance """