Merge "libvirt: Improve _is_booted_from_volume implementation"

This commit is contained in:
Jenkins 2016-12-07 13:13:40 +00:00 committed by Gerrit Code Review
commit 002dfa61df
2 changed files with 90 additions and 35 deletions

View File

@ -309,7 +309,8 @@ def fake_disk_info_byname(instance, type='qcow2'):
disk_info = OrderedDict()
# root disk
if instance.image_ref is not None:
if (instance.image_ref is not None and
instance.image_ref != uuids.fake_volume_backed_image_ref):
cache_name = imagecache.get_cache_fname(instance.image_ref)
disk_info['disk'] = {
'type': type,
@ -13676,7 +13677,6 @@ class LibvirtConnTestCase(test.NoDBTestCase):
self.assertEqual('/dev/nbd0', inst_sys_meta['rootfs_device_name'])
self.assertFalse(mock_instance.called)
mock_get_inst_path.assert_has_calls([mock.call(mock_instance)])
mock_is_booted_from_volume.assert_called_once_with(mock_instance, {})
mock_ensure_tree.assert_has_calls([mock.call('/tmp/rootfs')])
drvr.image_backend.by_name.assert_has_calls([mock.call(mock_instance,
'disk')])
@ -15347,22 +15347,52 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._disconnect_volume')
def test_migrate_disk_and_power_off_boot_from_volume(self,
disconnect_volume):
info = {'block_device_mapping': [{'boot_index': None,
'mount_device': '/dev/vdd',
'connection_info': None},
{'boot_index': 0,
'mount_device': '/dev/vda',
'connection_info': None}]}
info = {
'block_device_mapping': [
{'boot_index': None,
'mount_device': '/dev/vdd',
'connection_info': mock.sentinel.conn_info_vdd},
{'boot_index': 0,
'mount_device': '/dev/vda',
'connection_info': mock.sentinel.conn_info_vda}]}
flavor = {'root_gb': 1, 'ephemeral_gb': 0}
flavor_obj = objects.Flavor(**flavor)
# Note(Mike_D): The size of instance's ephemeral_gb is 0 gb.
self._test_migrate_disk_and_power_off(
flavor_obj, block_device_info=info,
params_for_instance={'image_ref': None,
'flavor': {'root_gb': 1,
'root_gb': 10,
'ephemeral_gb': 0,
'flavor': {'root_gb': 10,
'ephemeral_gb': 0}})
disconnect_volume.assert_called_with(
info['block_device_mapping'][1]['connection_info'], 'vda')
mock.sentinel.conn_info_vda, 'vda')
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._disconnect_volume')
def test_migrate_disk_and_power_off_boot_from_volume_backed_snapshot(
self, disconnect_volume):
# Such instance has not empty image_ref, but must be considered as
# booted from volume.
info = {
'block_device_mapping': [
{'boot_index': None,
'mount_device': '/dev/vdd',
'connection_info': mock.sentinel.conn_info_vdd},
{'boot_index': 0,
'mount_device': '/dev/vda',
'connection_info': mock.sentinel.conn_info_vda}]}
flavor = {'root_gb': 1, 'ephemeral_gb': 0}
flavor_obj = objects.Flavor(**flavor)
self._test_migrate_disk_and_power_off(
flavor_obj, block_device_info=info,
params_for_instance={
'image_ref': uuids.fake_volume_backed_image_ref,
'root_gb': 10,
'ephemeral_gb': 0,
'flavor': {'root_gb': 10,
'ephemeral_gb': 0}})
disconnect_volume.assert_called_with(
mock.sentinel.conn_info_vda, 'vda')
@mock.patch('nova.utils.execute')
@mock.patch('nova.virt.libvirt.utils.copy_image')
@ -15533,6 +15563,26 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
self.drvr.migrate_disk_and_power_off,
'ctx', instance, '10.0.0.1', flavor_obj, None)
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver'
'.get_instance_disk_info')
def test_migrate_disk_and_power_off_resize_error_rbd(self,
mock_get_disk_info):
# Check error on resize root disk down for rbd.
# The difference is that get_instance_disk_info always returns
# an emply list for rbd.
# Ephemeral size is not changed in this case (otherwise other check
# will raise the same error).
self.flags(images_type='rbd', group='libvirt')
instance = self._create_instance()
flavor = {'root_gb': 5, 'ephemeral_gb': 20}
flavor_obj = objects.Flavor(**flavor)
mock_get_disk_info.return_value = []
self.assertRaises(
exception.InstanceFaultRollback,
self.drvr.migrate_disk_and_power_off,
'ctx', instance, '10.0.0.1', flavor_obj, None)
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver'
'.get_instance_disk_info')
def test_migrate_disk_and_power_off_resize_error_default_ephemeral(
@ -16155,14 +16205,22 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
def test_is_booted_from_volume(self):
func = libvirt_driver.LibvirtDriver._is_booted_from_volume
instance, disk_mapping = {}, {}
bdm = []
bdi = {'block_device_mapping': bdm}
self.assertTrue(func(instance, disk_mapping))
disk_mapping['disk'] = 'map'
self.assertTrue(func(instance, disk_mapping))
self.assertFalse(func(bdi))
instance['image_ref'] = 'uuid'
self.assertFalse(func(instance, disk_mapping))
bdm.append({'boot_index': -1})
self.assertFalse(func(bdi))
bdm.append({'boot_index': None})
self.assertFalse(func(bdi))
bdm.append({'boot_index': 1})
self.assertFalse(func(bdi))
bdm.append({'boot_index': 0})
self.assertTrue(func(bdi))
@mock.patch('nova.virt.libvirt.driver.imagebackend')
@mock.patch(

View File

@ -2939,14 +2939,15 @@ class LibvirtDriver(driver.ComputeDriver):
return 'rbd' if CONF.libvirt.images_type == 'rbd' else 'raw'
@staticmethod
def _is_booted_from_volume(instance, disk_mapping):
def _is_booted_from_volume(block_device_info):
"""Determines whether the VM is booting from volume
Determines whether the disk mapping indicates that the VM
Determines whether the block device info indicates that the VM
is booting from a volume.
"""
return ((not bool(instance.get('image_ref')))
or 'disk' not in disk_mapping)
block_device_mapping = driver.block_device_info_get_mapping(
block_device_info)
return bool(block_device.get_root_bdm(block_device_mapping))
def _inject_data(self, injection_image, instance, network_info,
admin_pass, files):
@ -3011,8 +3012,7 @@ class LibvirtDriver(driver.ComputeDriver):
admin_pass=None, inject_files=True,
fallback_from_host=None,
ignore_bdi_for_swap=False):
booted_from_volume = self._is_booted_from_volume(
instance, disk_mapping)
booted_from_volume = self._is_booted_from_volume(block_device_info)
def image(fname, image_type=CONF.libvirt.images_type):
return self.image_backend.by_name(instance,
@ -4838,13 +4838,10 @@ class LibvirtDriver(driver.ComputeDriver):
def _create_domain_setup_lxc(self, instance, image_meta,
block_device_info, disk_info):
inst_path = libvirt_utils.get_instance_path(instance)
disk_info = disk_info or {}
disk_mapping = disk_info.get('mapping', {})
if self._is_booted_from_volume(instance, disk_mapping):
block_device_mapping = driver.block_device_info_get_mapping(
block_device_info)
root_disk = block_device.get_root_bdm(block_device_mapping)
block_device_mapping = driver.block_device_info_get_mapping(
block_device_info)
root_disk = block_device.get_root_bdm(block_device_mapping)
if root_disk:
disk_info = blockinfo.get_info_from_bdm(
instance, CONF.libvirt.virt_type, image_meta, root_disk)
self._connect_volume(root_disk['connection_info'], disk_info)
@ -7177,17 +7174,13 @@ class LibvirtDriver(driver.ComputeDriver):
# Checks if the migration needs a disk resize down.
root_down = flavor.root_gb < instance.flavor.root_gb
ephemeral_down = flavor.ephemeral_gb < eph_size
disk_info_text = self.get_instance_disk_info(
instance, block_device_info=block_device_info)
booted_from_volume = self._is_booted_from_volume(instance,
disk_info_text)
booted_from_volume = self._is_booted_from_volume(block_device_info)
if (root_down and not booted_from_volume) or ephemeral_down:
reason = _("Unable to resize disk down.")
raise exception.InstanceFaultRollback(
exception.ResizeError(reason=reason))
disk_info = jsonutils.loads(disk_info_text)
# NOTE(dgenin): Migration is not implemented for LVM backed instances.
if CONF.libvirt.images_type == 'lvm' and not booted_from_volume:
reason = _("Migration is not supported for LVM backed instances")
@ -7221,6 +7214,10 @@ class LibvirtDriver(driver.ComputeDriver):
disk_dev = vol['mount_device'].rpartition("/")[2]
self._disconnect_volume(connection_info, disk_dev)
disk_info_text = self.get_instance_disk_info(
instance, block_device_info=block_device_info)
disk_info = jsonutils.loads(disk_info_text)
try:
utils.execute('mv', inst_base, inst_base_resize)
# if we are migrating the instance with shared storage then