Fix live-migration when using ovs-vif-driver

When live-migrating a vm the ports are not added to the bridge
at the destination. This patch ensures that ports are added
correctly during live migration.

Closes-Bug: #1551222
(cherry picked from commit ce3e4e9317)
Change-Id: I70735ef1544622fbad2bf88d105192afe087a5b0
This commit is contained in:
Adelina Tuvenie 2015-12-10 04:49:42 +02:00
parent bf7069f72a
commit f8420ebe57
5 changed files with 75 additions and 24 deletions

View File

@ -160,6 +160,10 @@ class HyperVDriver(driver.ComputeDriver):
self._livemigrationops.post_live_migration(context, instance,
block_device_info)
def post_live_migration_at_source(self, context, instance, network_info):
"""Unplug VIFs from networks at source."""
self._vmops.unplug_vifs(instance, network_info)
def post_live_migration_at_destination(self, context, instance,
network_info,
block_migration=False,

View File

@ -112,6 +112,7 @@ class LiveMigrationOps(object):
network_info, block_migration):
LOG.debug("post_live_migration_at_destination called",
instance=instance_ref)
self._vmops.post_start_vifs(instance_ref, network_info)
@check_os_version_requirement
def check_can_live_migrate_destination(self, ctxt, instance_ref,

View File

@ -501,10 +501,7 @@ class VMOps(object):
if destroy_disks:
self._delete_disk_files(instance_name)
if network_info:
for vif in network_info:
vif_driver = self._get_vif_driver(vif.get('type'))
vif_driver.unplug(instance, vif)
self.unplug_vifs(instance, network_info)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_LE('Failed to destroy instance: %s'),
@ -612,10 +609,7 @@ class VMOps(object):
block_device_info)
self._set_vm_state(instance, constants.HYPERV_VM_STATE_ENABLED)
if network_info:
for vif in network_info:
vif_driver = self._get_vif_driver(vif.get('type'))
vif_driver.post_start(instance, vif)
self.post_start_vifs(instance, network_info)
def _set_vm_state(self, instance, req_state):
instance_name = instance.name
@ -788,6 +782,18 @@ class VMOps(object):
self.power_on(instance)
def unplug_vifs(self, instance, network_info):
if network_info:
for vif in network_info:
vif_driver = self._get_vif_driver(vif.get('type'))
vif_driver.unplug(instance, vif)
def post_start_vifs(self, instance, network_info):
if network_info:
for vif in network_info:
vif_driver = self._get_vif_driver(vif.get('type'))
vif_driver.post_start(instance, vif)
def _check_hotplug_is_available(self, instance):
if (self._get_vm_state(instance.name) ==
constants.HYPERV_VM_STATE_DISABLED):

View File

@ -121,3 +121,12 @@ class LiveMigrationOpsTestCase(test_base.HyperVBaseTestCase):
mock.sentinel.block_device_info)
self._livemigrops._pathutils.get_instance_dir.assert_called_once_with(
mock.sentinel.instance.name, create_dir=False, remove_dir=True)
@mock.patch.object(livemigrationops.vmops.VMOps, 'post_start_vifs')
def test_post_live_migration_at_destination(self, mock_post_start_vifs):
self._livemigrops.post_live_migration_at_destination(
mock.sentinel.context, mock.sentinel.instance,
mock.sentinel.network_info, mock.sentinel.block_migration)
mock_post_start_vifs.assert_called_once_with(
mock.sentinel.instance, mock.sentinel.network_info)

View File

@ -753,13 +753,15 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
@mock.patch('hyperv.nova.volumeops.VolumeOps.disconnect_volumes')
@mock.patch('hyperv.nova.vmops.VMOps._delete_disk_files')
@mock.patch('hyperv.nova.vmops.VMOps.power_off')
def test_destroy(self, mock_power_off, mock_delete_disk_files,
mock_disconnect_volumes):
@mock.patch('hyperv.nova.vmops.VMOps.unplug_vifs')
def test_destroy(self, mock_unplug_vifs, mock_power_off,
mock_delete_disk_files, mock_disconnect_volumes):
mock_instance = fake_instance.fake_instance_obj(self.context)
self._vmops._vmutils.vm_exists.return_value = True
self._vmops.destroy(instance=mock_instance,
block_device_info=mock.sentinel.FAKE_BD_INFO)
block_device_info=mock.sentinel.FAKE_BD_INFO,
network_info=mock.sentinel.fake_network_info)
self._vmops._vmutils.vm_exists.assert_called_with(
mock_instance.name)
@ -770,6 +772,8 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
mock.sentinel.FAKE_BD_INFO)
mock_delete_disk_files.assert_called_once_with(
mock_instance.name)
mock_unplug_vifs.assert_called_once_with(
mock_instance, mock.sentinel.fake_network_info)
def test_destroy_inexistent_instance(self):
mock_instance = fake_instance.fake_instance_obj(self.context)
@ -961,21 +965,14 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
mock_set_vm_state.assert_called_once_with(
mock_instance, constants.HYPERV_VM_STATE_ENABLED)
@mock.patch.object(vmops.VMOps, '_get_vif_driver')
def test_power_on_with_network_info(self, mock_get_vif_driver):
@mock.patch.object(vmops.VMOps, 'post_start_vifs')
def test_power_on_with_network_info(self, mock_post_start_vifs):
mock_instance = fake_instance.fake_instance_obj(self.context)
fake_vif1 = {'id': mock.sentinel.ID1,
'type': mock.sentinel.vif_type1}
fake_vif2 = {'id': mock.sentinel.ID2,
'type': mock.sentinel.vif_type2}
mock_network_info = [fake_vif1, fake_vif2]
fake_vif_driver = mock.MagicMock()
mock_get_vif_driver.return_value = fake_vif_driver
calls = [mock.call(mock_instance, fake_vif1),
mock.call(mock_instance, fake_vif2)]
self._vmops.power_on(mock_instance, network_info=mock_network_info)
fake_vif_driver.post_start.assert_has_calls(calls)
self._vmops.power_on(mock_instance,
network_info=mock.sentinel.fake_network_info)
mock_post_start_vifs.assert_called_once_with(
mock_instance, mock.sentinel.fake_network_info)
def _test_set_vm_state(self, state):
mock_instance = fake_instance.fake_instance_obj(self.context)
@ -1252,6 +1249,40 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
def test_configure_remotefx(self):
self._test_configure_remotefx()
@mock.patch.object(vmops.VMOps, '_get_vif_driver')
def test_unplug_vifs(self, mock_get_vif_driver):
mock_instance = fake_instance.fake_instance_obj(self.context)
fake_vif1 = {'id': mock.sentinel.ID1,
'type': mock.sentinel.vif_type1}
fake_vif2 = {'id': mock.sentinel.ID2,
'type': mock.sentinel.vif_type2}
mock_network_info = [fake_vif1, fake_vif2]
fake_vif_driver = mock.MagicMock()
mock_get_vif_driver.return_value = fake_vif_driver
calls = [mock.call(mock_instance, fake_vif1),
mock.call(mock_instance, fake_vif2)]
self._vmops.unplug_vifs(mock_instance,
network_info=mock_network_info)
fake_vif_driver.unplug.assert_has_calls(calls)
@mock.patch.object(vmops.VMOps, '_get_vif_driver')
def test_post_start_vifs(self, mock_get_vif_driver):
mock_instance = fake_instance.fake_instance_obj(self.context)
fake_vif1 = {'id': mock.sentinel.ID1,
'type': mock.sentinel.vif_type1}
fake_vif2 = {'id': mock.sentinel.ID2,
'type': mock.sentinel.vif_type2}
mock_network_info = [fake_vif1, fake_vif2]
fake_vif_driver = mock.MagicMock()
mock_get_vif_driver.return_value = fake_vif_driver
calls = [mock.call(mock_instance, fake_vif1),
mock.call(mock_instance, fake_vif2)]
self._vmops.post_start_vifs(mock_instance,
network_info=mock_network_info)
fake_vif_driver.post_start.assert_has_calls(calls)
@mock.patch.object(vmops.VMOps, '_get_vm_state')
def _test_check_hotplug_is_available(self, mock_get_vm_state, vm_gen,
windows_version, vm_state):