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() disk_info = OrderedDict()
# root disk # 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) cache_name = imagecache.get_cache_fname(instance.image_ref)
disk_info['disk'] = { disk_info['disk'] = {
'type': type, 'type': type,
@ -13676,7 +13677,6 @@ class LibvirtConnTestCase(test.NoDBTestCase):
self.assertEqual('/dev/nbd0', inst_sys_meta['rootfs_device_name']) self.assertEqual('/dev/nbd0', inst_sys_meta['rootfs_device_name'])
self.assertFalse(mock_instance.called) self.assertFalse(mock_instance.called)
mock_get_inst_path.assert_has_calls([mock.call(mock_instance)]) 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')]) mock_ensure_tree.assert_has_calls([mock.call('/tmp/rootfs')])
drvr.image_backend.by_name.assert_has_calls([mock.call(mock_instance, drvr.image_backend.by_name.assert_has_calls([mock.call(mock_instance,
'disk')]) 'disk')])
@ -15347,22 +15347,52 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._disconnect_volume') @mock.patch('nova.virt.libvirt.driver.LibvirtDriver._disconnect_volume')
def test_migrate_disk_and_power_off_boot_from_volume(self, def test_migrate_disk_and_power_off_boot_from_volume(self,
disconnect_volume): disconnect_volume):
info = {'block_device_mapping': [{'boot_index': None, info = {
'block_device_mapping': [
{'boot_index': None,
'mount_device': '/dev/vdd', 'mount_device': '/dev/vdd',
'connection_info': None}, 'connection_info': mock.sentinel.conn_info_vdd},
{'boot_index': 0, {'boot_index': 0,
'mount_device': '/dev/vda', 'mount_device': '/dev/vda',
'connection_info': None}]} 'connection_info': mock.sentinel.conn_info_vda}]}
flavor = {'root_gb': 1, 'ephemeral_gb': 0} flavor = {'root_gb': 1, 'ephemeral_gb': 0}
flavor_obj = objects.Flavor(**flavor) flavor_obj = objects.Flavor(**flavor)
# Note(Mike_D): The size of instance's ephemeral_gb is 0 gb. # Note(Mike_D): The size of instance's ephemeral_gb is 0 gb.
self._test_migrate_disk_and_power_off( self._test_migrate_disk_and_power_off(
flavor_obj, block_device_info=info, flavor_obj, block_device_info=info,
params_for_instance={'image_ref': None, params_for_instance={'image_ref': None,
'flavor': {'root_gb': 1, 'root_gb': 10,
'ephemeral_gb': 0,
'flavor': {'root_gb': 10,
'ephemeral_gb': 0}}) 'ephemeral_gb': 0}})
disconnect_volume.assert_called_with( 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.utils.execute')
@mock.patch('nova.virt.libvirt.utils.copy_image') @mock.patch('nova.virt.libvirt.utils.copy_image')
@ -15533,6 +15563,26 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
self.drvr.migrate_disk_and_power_off, self.drvr.migrate_disk_and_power_off,
'ctx', instance, '10.0.0.1', flavor_obj, None) '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' @mock.patch('nova.virt.libvirt.driver.LibvirtDriver'
'.get_instance_disk_info') '.get_instance_disk_info')
def test_migrate_disk_and_power_off_resize_error_default_ephemeral( 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): def test_is_booted_from_volume(self):
func = libvirt_driver.LibvirtDriver._is_booted_from_volume func = libvirt_driver.LibvirtDriver._is_booted_from_volume
instance, disk_mapping = {}, {} bdm = []
bdi = {'block_device_mapping': bdm}
self.assertTrue(func(instance, disk_mapping)) self.assertFalse(func(bdi))
disk_mapping['disk'] = 'map'
self.assertTrue(func(instance, disk_mapping))
instance['image_ref'] = 'uuid' bdm.append({'boot_index': -1})
self.assertFalse(func(instance, disk_mapping)) 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('nova.virt.libvirt.driver.imagebackend')
@mock.patch( @mock.patch(

View File

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