Fix live migration with shared storage
At the moment, when live migration is requested, we attempt to copy the instance dvd disks and log files to the remote location, other instance files being transparently copied by Hyper-V. The issue is that we don't check whether shared storage is being used, in which case this will fail. This change adds this check. Closes-Bug: #1565895 Change-Id: Ib646c90c830a1cd0e5401d14c6d400226b034f73
This commit is contained in:
parent
820f5f8ff4
commit
ba2b0bbda5
|
@ -51,13 +51,16 @@ class LiveMigrationOps(object):
|
|||
instance_name = instance_ref["name"]
|
||||
|
||||
try:
|
||||
self._vmops.copy_vm_dvd_disks(instance_name, dest)
|
||||
|
||||
# We must make sure that the console log workers are stopped,
|
||||
# otherwise we won't be able to delete / move VM log files.
|
||||
self._serial_console_ops.stop_console_handler(instance_name)
|
||||
|
||||
self._pathutils.copy_vm_console_logs(instance_name, dest)
|
||||
shared_storage = (
|
||||
self._pathutils.check_remote_instances_dir_shared(dest))
|
||||
if not shared_storage:
|
||||
self._vmops.copy_vm_dvd_disks(instance_name, dest)
|
||||
self._pathutils.copy_vm_console_logs(instance_name, dest)
|
||||
|
||||
self._livemigrutils.live_migrate_vm(instance_name,
|
||||
dest)
|
||||
except Exception:
|
||||
|
|
|
@ -202,3 +202,11 @@ class PathUtils(pathutils.PathUtils):
|
|||
"is local, thus it will not be handled as a "
|
||||
"loopback share.")
|
||||
LOG.exception(err_msg)
|
||||
|
||||
def check_remote_instances_dir_shared(self, dest):
|
||||
# Checks if the instances dir from a remote host points
|
||||
# to the same storage location as the local instances dir.
|
||||
local_inst_dir = self.get_instances_dir()
|
||||
remote_inst_dir = self.get_instances_dir(dest)
|
||||
return self.check_dirs_shared_storage(local_inst_dir,
|
||||
remote_inst_dir)
|
||||
|
|
|
@ -37,14 +37,19 @@ class LiveMigrationOpsTestCase(test_base.HyperVBaseTestCase):
|
|||
@mock.patch('hyperv.nova.serialconsoleops.SerialConsoleOps.'
|
||||
'stop_console_handler')
|
||||
@mock.patch('hyperv.nova.vmops.VMOps.copy_vm_dvd_disks')
|
||||
def _test_live_migration(self, mock_get_vm_dvd_paths,
|
||||
mock_stop_console_handler, side_effect):
|
||||
def _test_live_migration(self, mock_copy_dvd_disks,
|
||||
mock_stop_console_handler, side_effect=None,
|
||||
shared_storage=False):
|
||||
mock_instance = fake_instance.fake_instance_obj(self.context)
|
||||
mock_post = mock.MagicMock()
|
||||
mock_recover = mock.MagicMock()
|
||||
fake_dest = mock.sentinel.DESTINATION
|
||||
self._livemigrops._livemigrutils.live_migrate_vm.side_effect = [
|
||||
side_effect]
|
||||
mock_check_shared_storage = (
|
||||
self._livemigrops._pathutils.check_remote_instances_dir_shared)
|
||||
mock_check_shared_storage.return_value = shared_storage
|
||||
|
||||
if side_effect is os_win_exc.HyperVException:
|
||||
self.assertRaises(os_win_exc.HyperVException,
|
||||
self._livemigrops.live_migration,
|
||||
|
@ -61,9 +66,18 @@ class LiveMigrationOpsTestCase(test_base.HyperVBaseTestCase):
|
|||
|
||||
mock_stop_console_handler.assert_called_once_with(
|
||||
mock_instance.name)
|
||||
mock_check_shared_storage.assert_called_once_with(fake_dest)
|
||||
|
||||
mock_copy_logs = self._livemigrops._pathutils.copy_vm_console_logs
|
||||
mock_copy_logs.assert_called_once_with(mock_instance.name,
|
||||
fake_dest)
|
||||
if not shared_storage:
|
||||
mock_copy_logs.assert_called_once_with(mock_instance.name,
|
||||
fake_dest)
|
||||
mock_copy_dvd_disks.assert_called_once_with(
|
||||
mock_instance.name, fake_dest)
|
||||
else:
|
||||
self.assertFalse(mock_copy_logs.called)
|
||||
self.assertFalse(mock_copy_dvd_disks.called)
|
||||
|
||||
mock_live_migr = self._livemigrops._livemigrutils.live_migrate_vm
|
||||
mock_live_migr.assert_called_once_with(mock_instance.name,
|
||||
fake_dest)
|
||||
|
@ -71,7 +85,10 @@ class LiveMigrationOpsTestCase(test_base.HyperVBaseTestCase):
|
|||
fake_dest, False)
|
||||
|
||||
def test_live_migration(self):
|
||||
self._test_live_migration(side_effect=None)
|
||||
self._test_live_migration()
|
||||
|
||||
def test_live_migration_shared_storage(self):
|
||||
self._test_live_migration(shared_storage=True)
|
||||
|
||||
def test_live_migration_exception(self):
|
||||
self._test_live_migration(side_effect=os_win_exc.HyperVException)
|
||||
|
|
|
@ -207,3 +207,20 @@ class PathUtilsTestCase(test_base.HyperVBaseTestCase):
|
|||
local_share_path, share_address)
|
||||
else:
|
||||
self.assertFalse(mock_check_dirs_shared_storage.called)
|
||||
|
||||
@mock.patch.object(pathutils.PathUtils, 'check_dirs_shared_storage')
|
||||
@mock.patch.object(pathutils.PathUtils, 'get_instances_dir')
|
||||
def test_check_remote_instances_shared(self, mock_get_instances_dir,
|
||||
mock_check_dirs_shared_storage):
|
||||
mock_get_instances_dir.side_effect = [mock.sentinel.local_inst_dir,
|
||||
mock.sentinel.remote_inst_dir]
|
||||
|
||||
shared_storage = self._pathutils.check_remote_instances_dir_shared(
|
||||
mock.sentinel.dest)
|
||||
|
||||
self.assertEqual(mock_check_dirs_shared_storage.return_value,
|
||||
shared_storage)
|
||||
mock_get_instances_dir.assert_has_calls(
|
||||
[mock.call(), mock.call(mock.sentinel.dest)])
|
||||
mock_check_dirs_shared_storage.assert_called_once_with(
|
||||
mock.sentinel.local_inst_dir, mock.sentinel.remote_inst_dir)
|
||||
|
|
Loading…
Reference in New Issue