Disconnect from iSCSI volume sessions after live migration
The live migration source host will now disconnect from iSCSI volume sessions after the VM is successfully migrated to the destination host. Fixes bug 1132146 Change-Id: I132869612bdf2baa810756586e643ea68ea8d8f6
This commit is contained in:
parent
a4028e6a36
commit
38e6e93a81
@ -3846,6 +3846,11 @@ class ComputeManager(manager.SchedulerDependentManager):
|
||||
LOG.info(_('_post_live_migration() is started..'),
|
||||
instance=instance_ref)
|
||||
|
||||
# Cleanup source host post live-migration
|
||||
block_device_info = self._get_instance_volume_block_device_info(
|
||||
ctxt, instance_ref)
|
||||
self.driver.post_live_migration(ctxt, instance_ref, block_device_info)
|
||||
|
||||
# Detaching volumes.
|
||||
connector = self.driver.get_volume_connector(instance_ref)
|
||||
for bdm in self._get_instance_volume_bdms(ctxt, instance_ref):
|
||||
|
@ -19,6 +19,7 @@
|
||||
"""Tests for compute service."""
|
||||
|
||||
import base64
|
||||
import contextlib
|
||||
import copy
|
||||
import datetime
|
||||
import operator
|
||||
@ -28,6 +29,7 @@ import time
|
||||
import traceback
|
||||
import uuid
|
||||
|
||||
import mock
|
||||
import mox
|
||||
from oslo.config import cfg
|
||||
|
||||
@ -4345,32 +4347,35 @@ class ComputeTestCase(BaseTestCase):
|
||||
'power_state': power_state.PAUSED})
|
||||
|
||||
# creating mocks
|
||||
self.mox.StubOutWithMock(self.compute.driver, 'unfilter_instance')
|
||||
self.compute.driver.unfilter_instance(inst_ref, [])
|
||||
self.mox.StubOutWithMock(self.compute.conductor_api,
|
||||
'network_migrate_instance_start')
|
||||
migration = {'source_compute': srchost,
|
||||
'dest_compute': dest, }
|
||||
self.compute.conductor_api.network_migrate_instance_start(c, inst_ref,
|
||||
migration)
|
||||
with contextlib.nested(
|
||||
mock.patch.object(self.compute.driver, 'post_live_migration'),
|
||||
mock.patch.object(self.compute.driver, 'unfilter_instance'),
|
||||
mock.patch.object(self.compute.conductor_api,
|
||||
'network_migrate_instance_start'),
|
||||
mock.patch.object(self.compute.compute_rpcapi,
|
||||
'post_live_migration_at_destination'),
|
||||
mock.patch.object(self.compute.driver, 'unplug_vifs'),
|
||||
mock.patch.object(self.compute.network_api,
|
||||
'setup_networks_on_host')
|
||||
) as (
|
||||
post_live_migration, unfilter_instance,
|
||||
network_migrate_instance_start, post_live_migration_at_destination,
|
||||
unplug_vifs, setup_networks_on_host
|
||||
):
|
||||
self.compute._post_live_migration(c, inst_ref, dest)
|
||||
|
||||
self.mox.StubOutWithMock(self.compute.compute_rpcapi,
|
||||
'post_live_migration_at_destination')
|
||||
self.compute.compute_rpcapi.post_live_migration_at_destination(
|
||||
c, inst_ref, False, dest)
|
||||
|
||||
self.mox.StubOutWithMock(self.compute.driver, 'unplug_vifs')
|
||||
self.compute.driver.unplug_vifs(inst_ref, [])
|
||||
|
||||
self.mox.StubOutWithMock(self.compute.network_api,
|
||||
'setup_networks_on_host')
|
||||
self.compute.network_api.setup_networks_on_host(c, inst_ref,
|
||||
self.compute.host,
|
||||
teardown=True)
|
||||
|
||||
# start test
|
||||
self.mox.ReplayAll()
|
||||
self.compute._post_live_migration(c, inst_ref, dest)
|
||||
post_live_migration.assert_has_calls([
|
||||
mock.call(c, inst_ref, {'block_device_mapping': []})])
|
||||
unfilter_instance.assert_has_calls([mock.call(inst_ref, [])])
|
||||
migration = {'source_compute': srchost,
|
||||
'dest_compute': dest, }
|
||||
network_migrate_instance_start.assert_has_calls([
|
||||
mock.call(c, inst_ref, migration)])
|
||||
post_live_migration_at_destination.assert_has_calls([
|
||||
mock.call(c, inst_ref, False, dest)])
|
||||
unplug_vifs.assert_has_calls([mock.call(inst_ref, [])])
|
||||
setup_networks_on_host.assert_has_calls([
|
||||
mock.call(c, inst_ref, self.compute.host, teardown=True)])
|
||||
|
||||
def _begin_post_live_migration_at_destination(self):
|
||||
self.mox.StubOutWithMock(self.compute.network_api,
|
||||
|
@ -15,6 +15,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import contextlib
|
||||
import copy
|
||||
import errno
|
||||
import eventlet
|
||||
@ -27,6 +28,7 @@ import tempfile
|
||||
|
||||
from eventlet import greenthread
|
||||
from lxml import etree
|
||||
import mock
|
||||
from oslo.config import cfg
|
||||
from xml.dom import minidom
|
||||
|
||||
@ -2757,6 +2759,31 @@ class LibvirtConnTestCase(test.TestCase):
|
||||
|
||||
db.instance_destroy(self.context, instance_ref['uuid'])
|
||||
|
||||
def test_post_live_migration(self):
|
||||
vol = {'block_device_mapping': [
|
||||
{'connection_info': 'dummy1', 'mount_device': '/dev/sda'},
|
||||
{'connection_info': 'dummy2', 'mount_device': '/dev/sdb'}]}
|
||||
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
||||
|
||||
inst_ref = {'id': 'foo'}
|
||||
cntx = context.get_admin_context()
|
||||
|
||||
# Set up the mock expectations
|
||||
with contextlib.nested(
|
||||
mock.patch.object(driver, 'block_device_info_get_mapping',
|
||||
return_value=vol['block_device_mapping']),
|
||||
mock.patch.object(conn, 'volume_driver_method')
|
||||
) as (block_device_info_get_mapping, volume_driver_method):
|
||||
conn.post_live_migration(cntx, inst_ref, vol)
|
||||
|
||||
block_device_info_get_mapping.assert_has_calls([
|
||||
mock.call(vol)])
|
||||
volume_driver_method.assert_has_calls([
|
||||
mock.call('disconnect_volume',
|
||||
v['connection_info'],
|
||||
v['mount_device'].rpartition("/")[2])
|
||||
for v in vol['block_device_mapping']])
|
||||
|
||||
def test_get_instance_disk_info_excludes_volumes(self):
|
||||
# Test data
|
||||
instance_ref = db.instance_create(self.context, self.test_instance)
|
||||
|
@ -514,6 +514,15 @@ class ComputeDriver(object):
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def post_live_migration(self, ctxt, instance_ref, block_device_info):
|
||||
"""Post operation of live migration at source host.
|
||||
|
||||
:param ctxt: security contet
|
||||
:instance_ref: instance object that was migrated
|
||||
:block_device_info: instance block device information
|
||||
"""
|
||||
pass
|
||||
|
||||
def post_live_migration_at_destination(self, ctxt, instance_ref,
|
||||
network_info,
|
||||
block_migration=False,
|
||||
|
@ -3572,6 +3572,17 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
# following normal way.
|
||||
self._fetch_instance_kernel_ramdisk(context, instance)
|
||||
|
||||
def post_live_migration(self, context, instance, block_device_info):
|
||||
# Disconnect from volume server
|
||||
block_device_mapping = driver.block_device_info_get_mapping(
|
||||
block_device_info)
|
||||
for vol in block_device_mapping:
|
||||
connection_info = vol['connection_info']
|
||||
disk_dev = vol['mount_device'].rpartition("/")[2]
|
||||
self.volume_driver_method('disconnect_volume',
|
||||
connection_info,
|
||||
disk_dev)
|
||||
|
||||
def post_live_migration_at_destination(self, context,
|
||||
instance,
|
||||
network_info,
|
||||
|
@ -3,6 +3,7 @@ coverage>=3.6
|
||||
discover
|
||||
feedparser
|
||||
fixtures>=0.3.12
|
||||
mock>=1.0
|
||||
mox==0.5.3
|
||||
MySQL-python
|
||||
psycopg2
|
||||
|
Loading…
x
Reference in New Issue
Block a user