Merge "Disconnect from iSCSI volume sessions after live migration"

This commit is contained in:
Jenkins 2013-09-02 07:10:30 +00:00 committed by Gerrit Code Review
commit f145d8a963
5 changed files with 82 additions and 25 deletions

View File

@ -3901,6 +3901,11 @@ class ComputeManager(manager.SchedulerDependentManager):
LOG.info(_('_post_live_migration() is started..'), LOG.info(_('_post_live_migration() is started..'),
instance=instance_ref) 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. # Detaching volumes.
connector = self.driver.get_volume_connector(instance_ref) connector = self.driver.get_volume_connector(instance_ref)
for bdm in self._get_instance_volume_bdms(ctxt, instance_ref): for bdm in self._get_instance_volume_bdms(ctxt, instance_ref):

View File

@ -19,6 +19,7 @@
"""Tests for compute service.""" """Tests for compute service."""
import base64 import base64
import contextlib
import copy import copy
import datetime import datetime
import operator import operator
@ -28,6 +29,7 @@ import time
import traceback import traceback
import uuid import uuid
import mock
import mox import mox
from oslo.config import cfg from oslo.config import cfg
@ -4243,32 +4245,35 @@ class ComputeTestCase(BaseTestCase):
'power_state': power_state.PAUSED}) 'power_state': power_state.PAUSED})
# creating mocks # creating mocks
self.mox.StubOutWithMock(self.compute.driver, 'unfilter_instance') with contextlib.nested(
self.compute.driver.unfilter_instance(inst_ref, []) mock.patch.object(self.compute.driver, 'post_live_migration'),
self.mox.StubOutWithMock(self.compute.conductor_api, mock.patch.object(self.compute.driver, 'unfilter_instance'),
'network_migrate_instance_start') 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)
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, migration = {'source_compute': srchost,
'dest_compute': dest, } 'dest_compute': dest, }
self.compute.conductor_api.network_migrate_instance_start(c, inst_ref, network_migrate_instance_start.assert_has_calls([
migration) mock.call(c, inst_ref, migration)])
post_live_migration_at_destination.assert_has_calls([
self.mox.StubOutWithMock(self.compute.compute_rpcapi, mock.call(c, inst_ref, False, dest)])
'post_live_migration_at_destination') unplug_vifs.assert_has_calls([mock.call(inst_ref, [])])
self.compute.compute_rpcapi.post_live_migration_at_destination( setup_networks_on_host.assert_has_calls([
c, inst_ref, False, dest) mock.call(c, inst_ref, self.compute.host, teardown=True)])
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)
def _begin_post_live_migration_at_destination(self): def _begin_post_live_migration_at_destination(self):
self.mox.StubOutWithMock(self.compute.network_api, self.mox.StubOutWithMock(self.compute.network_api,

View File

@ -15,6 +15,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import contextlib
import copy import copy
import errno import errno
import eventlet import eventlet
@ -27,6 +28,7 @@ import tempfile
from eventlet import greenthread from eventlet import greenthread
from lxml import etree from lxml import etree
import mock
from oslo.config import cfg from oslo.config import cfg
from xml.dom import minidom from xml.dom import minidom
@ -2868,6 +2870,31 @@ class LibvirtConnTestCase(test.TestCase):
db.instance_destroy(self.context, instance_ref['uuid']) 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): def test_get_instance_disk_info_excludes_volumes(self):
# Test data # Test data
instance_ref = db.instance_create(self.context, self.test_instance) instance_ref = db.instance_create(self.context, self.test_instance)

View File

@ -514,6 +514,15 @@ class ComputeDriver(object):
""" """
raise NotImplementedError() 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, def post_live_migration_at_destination(self, ctxt, instance_ref,
network_info, network_info,
block_migration=False, block_migration=False,

View File

@ -3687,6 +3687,17 @@ class LibvirtDriver(driver.ComputeDriver):
# following normal way. # following normal way.
self._fetch_instance_kernel_ramdisk(context, instance) 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, def post_live_migration_at_destination(self, context,
instance, instance,
network_info, network_info,