From 177e9ff722019d41fa02eb515735d996ce5eed6a Mon Sep 17 00:00:00 2001 From: Hiroyuki Eguchi Date: Wed, 5 Aug 2015 21:32:08 +0900 Subject: [PATCH] allow live migration in case of a booted from volume instance A BadRequest error always occurr in case of a non shared storage environment even if the instance is booted from volume. We should allow user to execute live migration in case of a booted from volume instance. Closes-Bug: #1469006 Change-Id: I7989128d5bfa027c8f566c9d66956b1c4d328db5 --- nova/tests/unit/virt/libvirt/test_driver.py | 29 +++++++++++++++++++-- nova/virt/libvirt/driver.py | 27 +++++++++++++++++-- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 17247fe7b48e..7547c5cce289 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -5373,8 +5373,10 @@ class LibvirtConnTestCase(test.NoDBTestCase): def _mock_can_live_migrate_source(self, block_migration=False, is_shared_block_storage=False, is_shared_instance_path=False, + is_booted_from_volume=False, disk_available_mb=1024, - block_device_info=None): + block_device_info=None, + block_device_text=None): instance = objects.Instance(**self.test_instance) dest_check_data = {'filename': 'file', 'image_type': 'default', @@ -5389,6 +5391,13 @@ class LibvirtConnTestCase(test.NoDBTestCase): self.mox.StubOutWithMock(drvr, '_check_shared_storage_test_file') drvr._check_shared_storage_test_file('file').AndReturn( is_shared_instance_path) + self.mox.StubOutWithMock(drvr, "get_instance_disk_info") + drvr.get_instance_disk_info(instance, + block_device_info=block_device_info).\ + AndReturn(block_device_text) + self.mox.StubOutWithMock(drvr, '_is_booted_from_volume') + drvr._is_booted_from_volume(instance, block_device_text).AndReturn( + is_booted_from_volume) return (instance, dest_check_data, drvr) @@ -5463,7 +5472,6 @@ class LibvirtConnTestCase(test.NoDBTestCase): block_migration=True, disk_available_mb=0) - self.mox.StubOutWithMock(drvr, "get_instance_disk_info") drvr.get_instance_disk_info(instance, block_device_info=None).AndReturn( '[{"virt_disk_size":2}]') @@ -5473,6 +5481,23 @@ class LibvirtConnTestCase(test.NoDBTestCase): drvr.check_can_live_migrate_source, self.context, instance, dest_check_data) + def test_check_can_live_migrate_source_booted_from_volume(self): + instance, dest_check_data, drvr = self._mock_can_live_migrate_source( + is_booted_from_volume=True, + block_device_text='[]') + self.mox.ReplayAll() + drvr.check_can_live_migrate_source(self.context, instance, + dest_check_data) + + def test_check_can_live_migrate_source_booted_from_volume_with_swap(self): + instance, dest_check_data, drvr = self._mock_can_live_migrate_source( + is_booted_from_volume=True, + block_device_text='[{"path":"disk.swap"}]') + self.mox.ReplayAll() + self.assertRaises(exception.InvalidSharedStorage, + drvr.check_can_live_migrate_source, + self.context, instance, dest_check_data) + def _is_shared_block_storage_test_create_mocks(self, disks): # Test data instance_xml = ("instance-0000000a" diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 9afa544821d9..ef4dab319933 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -2630,6 +2630,20 @@ class LibvirtDriver(driver.ComputeDriver): return ((not bool(instance.get('image_ref'))) or 'disk' not in disk_mapping) + @staticmethod + def _has_local_disk(instance, disk_mapping): + """Determines whether the VM has a local disk + + Determines whether the disk mapping indicates that the VM + has a local disk (e.g. ephemeral, swap disk and config-drive). + """ + if disk_mapping: + if ('disk.local' in disk_mapping or + 'disk.swap' in disk_mapping or + 'disk.config' in disk_mapping): + return True + return False + def _inject_data(self, instance, network_info, admin_pass, files, suffix): """Injects data in a disk image @@ -5034,6 +5048,12 @@ class LibvirtDriver(driver.ComputeDriver): self._is_shared_block_storage(instance, dest_check_data, block_device_info)}) + 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) + has_local_disk = self._has_local_disk(instance, disk_info_text) + if dest_check_data['block_migration']: if (dest_check_data['is_shared_block_storage'] or dest_check_data['is_shared_instance_path']): @@ -5046,9 +5066,12 @@ class LibvirtDriver(driver.ComputeDriver): block_device_info) elif not (dest_check_data['is_shared_block_storage'] or - dest_check_data['is_shared_instance_path']): + dest_check_data['is_shared_instance_path'] or + (booted_from_volume and not has_local_disk)): reason = _("Live migration can not be used " - "without shared storage.") + "without shared storage except " + "a booted from volume VM which " + "does not have a local disk.") raise exception.InvalidSharedStorage(reason=reason, path=source) # NOTE(mikal): include the instance directory name here because it