Actually pass the migration data object down to the virt drivers

This makes the compute manager actually pass the objects down to the
virt drivers and makes the virt drivers use objects natively.

Related to blueprint objectify-live-migrate-data

Change-Id: I620d59b2f846e1c577f6714a84e32ac6df2d6fee
This commit is contained in:
Dan Smith 2015-11-20 10:22:24 -08:00
parent 5dd9b23e6b
commit 69e0175807
7 changed files with 218 additions and 164 deletions

View File

@ -5109,7 +5109,10 @@ class ComputeManager(manager.Manager):
migrate_data) migrate_data)
if isinstance(pre_live_migration_data, if isinstance(pre_live_migration_data,
migrate_data_obj.LiveMigrateData): migrate_data_obj.LiveMigrateData):
pre_live_migration_data = pre_live_migration_data.to_legacy_dict() pre_live_migration_data = pre_live_migration_data.to_legacy_dict(
pre_migration_result=True)
pre_live_migration_data = pre_live_migration_data[
'pre_live_migration_result']
# NOTE(tr3buchet): setup networks on destination host # NOTE(tr3buchet): setup networks on destination host
self.network_api.setup_networks_on_host(context, instance, self.network_api.setup_networks_on_host(context, instance,
@ -5130,6 +5133,21 @@ class ComputeManager(manager.Manager):
return pre_live_migration_data return pre_live_migration_data
def _get_migrate_data_obj(self):
# FIXME(danms): A couple patches from now, we'll be able to
# avoid this failure _if_ we get a new-style call with the
# object.
if CONF.compute_driver.startswith('libvirt'):
return objects.LibvirtLiveMigrateData()
elif CONF.compute_driver.startswith('xenapi'):
return objects.XenapiLiveMigrateData()
else:
LOG.error(_('Older RPC caller and unsupported virt driver in '
'use. Unable to handle this!'))
raise exception.MigrationError(
_('Unknown compute driver while providing compatibility '
'with older RPC formats'))
def _do_live_migration(self, context, dest, instance, block_migration, def _do_live_migration(self, context, dest, instance, block_migration,
migration, migrate_data): migration, migrate_data):
# NOTE(danms): We should enhance the RT to account for migrations # NOTE(danms): We should enhance the RT to account for migrations
@ -5153,7 +5171,8 @@ class ComputeManager(manager.Manager):
context, instance, context, instance,
block_migration, disk, dest, migrate_data) block_migration, disk, dest, migrate_data)
migrate_data['pre_live_migration_result'] = pre_migration_data migrate_data['pre_live_migration_result'] = pre_migration_data
migrate_data_obj = self._get_migrate_data_obj()
migrate_data_obj.from_legacy_dict(migrate_data)
except Exception: except Exception:
with excutils.save_and_reraise_exception(): with excutils.save_and_reraise_exception():
LOG.exception(_LE('Pre live migration failed at %s'), LOG.exception(_LE('Pre live migration failed at %s'),
@ -5164,12 +5183,12 @@ class ComputeManager(manager.Manager):
self._set_migration_status(migration, 'running') self._set_migration_status(migration, 'running')
migrate_data['migration'] = migration migrate_data_obj.migration = migration
try: try:
self.driver.live_migration(context, instance, dest, self.driver.live_migration(context, instance, dest,
self._post_live_migration, self._post_live_migration,
self._rollback_live_migration, self._rollback_live_migration,
block_migration, migrate_data) block_migration, migrate_data_obj)
except Exception: except Exception:
# Executing live migration # Executing live migration
# live_migration might raises exceptions, but # live_migration might raises exceptions, but
@ -5226,11 +5245,9 @@ class ComputeManager(manager.Manager):
# block storage or instance path were shared # block storage or instance path were shared
is_shared_block_storage = not block_migration is_shared_block_storage = not block_migration
is_shared_instance_path = not block_migration is_shared_instance_path = not block_migration
if migrate_data: if isinstance(migrate_data, objects.LibvirtLiveMigrateData):
is_shared_block_storage = migrate_data.get( is_shared_block_storage = migrate_data.is_shared_block_storage
'is_shared_block_storage', is_shared_block_storage) is_shared_instance_path = migrate_data.is_shared_instance_path
is_shared_instance_path = migrate_data.get(
'is_shared_instance_path', is_shared_instance_path)
# No instance booting at source host, but instance dir # No instance booting at source host, but instance dir
# must be deleted for preparing next block migration # must be deleted for preparing next block migration
@ -5347,9 +5364,9 @@ class ComputeManager(manager.Manager):
instance=instance) instance=instance)
self._clean_instance_console_tokens(ctxt, instance) self._clean_instance_console_tokens(ctxt, instance)
if migrate_data and migrate_data.get('migration'): if migrate_data and migrate_data.obj_attr_is_set('migration'):
migrate_data['migration'].status = 'completed' migrate_data.migration.status = 'completed'
migrate_data['migration'].save() migrate_data.migration.save()
def _consoles_enabled(self): def _consoles_enabled(self):
"""Returns whether a console is enable.""" """Returns whether a console is enable."""
@ -5450,8 +5467,10 @@ class ComputeManager(manager.Manager):
# NOTE(danms): Pop out the migration object so we don't pass # NOTE(danms): Pop out the migration object so we don't pass
# it over RPC unintentionally below # it over RPC unintentionally below
if migrate_data: if isinstance(migrate_data, dict):
migration = migrate_data.pop('migration', None) migration = migrate_data.pop('migration', None)
elif isinstance(migrate_data, migrate_data_obj.LiveMigrateData):
migration = migrate_data.migration
else: else:
migration = None migration = None
@ -5472,6 +5491,8 @@ class ComputeManager(manager.Manager):
block_migration, migrate_data) block_migration, migrate_data)
if do_cleanup: if do_cleanup:
if isinstance(migrate_data, migrate_data_obj.LiveMigrateData):
migrate_data = migrate_data.to_legacy_dict()
self.compute_rpcapi.rollback_live_migration_at_destination( self.compute_rpcapi.rollback_live_migration_at_destination(
context, instance, dest, destroy_disks=destroy_disks, context, instance, dest, destroy_disks=destroy_disks,
migrate_data=migrate_data) migrate_data=migrate_data)

View File

@ -68,6 +68,7 @@ from nova.network.security_group import openstack_driver
from nova import objects from nova import objects
from nova.objects import block_device as block_device_obj from nova.objects import block_device as block_device_obj
from nova.objects import instance as instance_obj from nova.objects import instance as instance_obj
from nova.objects import migrate_data as migrate_data_obj
from nova import policy from nova import policy
from nova import quota from nova import quota
from nova.scheduler import client as scheduler_client from nova.scheduler import client as scheduler_client
@ -5625,6 +5626,8 @@ class ComputeTestCase(BaseTestCase):
migration = objects.Migration() migration = objects.Migration()
with mock.patch.object(self.compute, '_get_migrate_data_obj') as gmdo:
gmdo.return_value = migrate_data_obj.LiveMigrateData()
ret = self.compute.live_migration(c, dest=dest, ret = self.compute.live_migration(c, dest=dest,
instance=instance, instance=instance,
block_migration=False, block_migration=False,
@ -5688,7 +5691,10 @@ class ComputeTestCase(BaseTestCase):
# start test # start test
self.mox.ReplayAll() self.mox.ReplayAll()
migrate_data = {'is_shared_instance_path': False} migrate_data = objects.LibvirtLiveMigrateData(
is_shared_instance_path=False,
is_shared_block_storage=False,
block_migration=False)
self.compute._post_live_migration(c, instance, dest, self.compute._post_live_migration(c, instance, dest,
migrate_data=migrate_data) migrate_data=migrate_data)
self.assertIn('cleanup', result) self.assertIn('cleanup', result)
@ -5711,7 +5717,9 @@ class ComputeTestCase(BaseTestCase):
'power_state': power_state.PAUSED}) 'power_state': power_state.PAUSED})
instance.save() instance.save()
migrate_data = {'migration': mock.MagicMock()} migration_obj = objects.Migration()
migrate_data = migrate_data_obj.LiveMigrateData(
migration=migration_obj)
# creating mocks # creating mocks
with test.nested( with test.nested(
@ -5727,12 +5735,13 @@ class ComputeTestCase(BaseTestCase):
'setup_networks_on_host'), 'setup_networks_on_host'),
mock.patch.object(self.compute.instance_events, mock.patch.object(self.compute.instance_events,
'clear_events_for_instance'), 'clear_events_for_instance'),
mock.patch.object(self.compute, 'update_available_resource') mock.patch.object(self.compute, 'update_available_resource'),
mock.patch.object(migration_obj, 'save'),
) as ( ) as (
post_live_migration, unfilter_instance, post_live_migration, unfilter_instance,
migrate_instance_start, post_live_migration_at_destination, migrate_instance_start, post_live_migration_at_destination,
post_live_migration_at_source, setup_networks_on_host, post_live_migration_at_source, setup_networks_on_host,
clear_events, update_available_resource clear_events, update_available_resource, mig_save
): ):
self.compute._post_live_migration(c, instance, dest, self.compute._post_live_migration(c, instance, dest,
migrate_data=migrate_data) migrate_data=migrate_data)
@ -5753,8 +5762,8 @@ class ComputeTestCase(BaseTestCase):
[mock.call(c, instance, [])]) [mock.call(c, instance, [])])
clear_events.assert_called_once_with(instance) clear_events.assert_called_once_with(instance)
update_available_resource.assert_has_calls([mock.call(c)]) update_available_resource.assert_has_calls([mock.call(c)])
self.assertEqual('completed', migrate_data['migration'].status) self.assertEqual('completed', migration_obj.status)
migrate_data['migration'].save.assert_called_once_with() mig_save.assert_called_once_with()
def test_post_live_migration_terminate_volume_connections(self): def test_post_live_migration_terminate_volume_connections(self):
c = context.get_admin_context() c = context.get_admin_context()

View File

@ -176,9 +176,10 @@ class _TestLibvirtLiveMigrateData(object):
serial_listen_addr='127.0.0.1', serial_listen_addr='127.0.0.1',
bdms=[test_bdmi]) bdms=[test_bdmi])
obj2 = migrate_data.LibvirtLiveMigrateData() obj2 = migrate_data.LibvirtLiveMigrateData()
obj2.from_legacy_dict(obj.to_legacy_dict()) obj2.from_legacy_dict(obj.to_legacy_dict(pre_migration_result=True))
self.assertEqual(obj.to_legacy_dict(), self.assertEqual(obj.to_legacy_dict(),
obj2.to_legacy_dict()) obj2.to_legacy_dict())
self.assertEqual(obj.bdms[0].serial, obj2.bdms[0].serial)
class TestLibvirtLiveMigrateData(test_objects._LocalTest, class TestLibvirtLiveMigrateData(test_objects._LocalTest,

View File

@ -6523,6 +6523,11 @@ class LibvirtConnTestCase(test.NoDBTestCase):
migrate_data = {'pre_live_migration_result': migrate_data = {'pre_live_migration_result':
{'graphics_listen_addrs': {'graphics_listen_addrs':
{'vnc': '10.0.0.1', 'spice': '10.0.0.2'}}} {'vnc': '10.0.0.1', 'spice': '10.0.0.2'}}}
migrate_data = objects.LibvirtLiveMigrateData(
graphics_listen_addr_vnc='10.0.0.1',
graphics_listen_addr_spice='10.0.0.2',
serial_listen_addr='127.0.0.1',
bdms=[])
self.mox.ReplayAll() self.mox.ReplayAll()
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
self.assertRaises(fakelibvirt.libvirtError, self.assertRaises(fakelibvirt.libvirtError,
@ -6542,21 +6547,24 @@ class LibvirtConnTestCase(test.NoDBTestCase):
'ip-1.2.3.4:3260-iqn.' 'ip-1.2.3.4:3260-iqn.'
'cde.67890.opst-lun-Z') 'cde.67890.opst-lun-Z')
# start test # start test
migrate_data = {'pre_live_migration_result': connection_info = {
{'volume': {u'58a84f6d-3f0c-4e19-a0af-eb657b790657': u'driver_volume_type': u'iscsi',
{'connection_info': {u'driver_volume_type': u'iscsi', u'serial': u'58a84f6d-3f0c-4e19-a0af-eb657b790657',
'serial': u'58a84f6d-3f0c-4e19-a0af-eb657b790657', u'data': {
u'data': {u'access_mode': u'rw', u'target_discovered': False, u'access_mode': u'rw', u'target_discovered': False,
u'target_iqn': u'ip-1.2.3.4:3260-iqn.cde.67890.opst-lun-Z', u'target_iqn': u'ip-1.2.3.4:3260-iqn.cde.67890.opst-lun-Z',
u'volume_id': u'58a84f6d-3f0c-4e19-a0af-eb657b790657', u'volume_id': u'58a84f6d-3f0c-4e19-a0af-eb657b790657',
'device_path': 'device_path':
u'/dev/disk/by-path/ip-1.2.3.4:3260-iqn.cde.67890.opst-lun-Z'}}, u'/dev/disk/by-path/ip-1.2.3.4:3260-iqn.cde.67890.opst-lun-Z',
'disk_info': {'bus': u'virtio', 'type': u'disk', 'dev': u'vdb'}}}}, },
'graphics_listen_addrs': {}} }
bdm = objects.LibvirtLiveMigrateBDMInfo(
pre_live_migrate_data = ((migrate_data or {}). serial='58a84f6d-3f0c-4e19-a0af-eb657b790657',
get('pre_live_migration_result', {})) bus='virtio', type='disk', dev='vdb',
volume = pre_live_migrate_data.get('volume') connection_info=connection_info)
migrate_data = objects.LibvirtLiveMigrateData(
serial_listen_addr='',
bdms=[bdm])
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
test_mock = mock.MagicMock() test_mock = mock.MagicMock()
@ -6574,7 +6582,8 @@ class LibvirtConnTestCase(test.NoDBTestCase):
self.assertFalse(drvr._live_migration_operation( self.assertFalse(drvr._live_migration_operation(
self.context, instance_ref, 'dest', False, self.context, instance_ref, 'dest', False,
migrate_data, test_mock)) migrate_data, test_mock))
mupdate.assert_called_once_with(target_xml, volume, None, None) mupdate.assert_called_once_with(target_xml, migrate_data.bdms,
{}, '')
def test_update_volume_xml(self): def test_update_volume_xml(self):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
@ -6589,40 +6598,35 @@ class LibvirtConnTestCase(test.NoDBTestCase):
'cde.67890.opst-lun-Z') 'cde.67890.opst-lun-Z')
target_xml = etree.tostring(etree.fromstring(target_xml)) target_xml = etree.tostring(etree.fromstring(target_xml))
serial = "58a84f6d-3f0c-4e19-a0af-eb657b790657" serial = "58a84f6d-3f0c-4e19-a0af-eb657b790657"
volume_xml = {'volume': {}}
volume_xml['volume'][serial] = {'connection_info': {}, 'disk_info': {}} bdmi = objects.LibvirtLiveMigrateBDMInfo(serial=serial,
volume_xml['volume'][serial]['connection_info'] = \ bus='virtio',
{u'driver_volume_type': u'iscsi', type='disk',
dev='vdb')
bdmi.connection_info = {u'driver_volume_type': u'iscsi',
'serial': u'58a84f6d-3f0c-4e19-a0af-eb657b790657', 'serial': u'58a84f6d-3f0c-4e19-a0af-eb657b790657',
u'data': {u'access_mode': u'rw', u'target_discovered': False, u'data': {u'access_mode': u'rw', u'target_discovered': False,
u'target_iqn': u'ip-1.2.3.4:3260-iqn.cde.67890.opst-lun-Z', u'target_iqn': u'ip-1.2.3.4:3260-iqn.cde.67890.opst-lun-Z',
u'volume_id': u'58a84f6d-3f0c-4e19-a0af-eb657b790657', u'volume_id': u'58a84f6d-3f0c-4e19-a0af-eb657b790657',
'device_path': 'device_path':
u'/dev/disk/by-path/ip-1.2.3.4:3260-iqn.cde.67890.opst-lun-Z'}} u'/dev/disk/by-path/ip-1.2.3.4:3260-iqn.cde.67890.opst-lun-Z'}}
volume_xml['volume'][serial]['disk_info'] = {'bus': u'virtio',
'type': u'disk',
'dev': u'vdb'}
connection_info = volume_xml['volume'][serial]['connection_info']
disk_info = volume_xml['volume'][serial]['disk_info']
conf = vconfig.LibvirtConfigGuestDisk() conf = vconfig.LibvirtConfigGuestDisk()
conf.source_device = disk_info['type'] conf.source_device = bdmi.type
conf.driver_name = "qemu" conf.driver_name = "qemu"
conf.driver_format = "raw" conf.driver_format = "raw"
conf.driver_cache = "none" conf.driver_cache = "none"
conf.target_dev = disk_info['dev'] conf.target_dev = bdmi.dev
conf.target_bus = disk_info['bus'] conf.target_bus = bdmi.bus
conf.serial = connection_info.get('serial') conf.serial = bdmi.connection_info.get('serial')
conf.source_type = "block" conf.source_type = "block"
conf.source_path = connection_info['data'].get('device_path') conf.source_path = bdmi.connection_info['data'].get('device_path')
with mock.patch.object(drvr, '_get_volume_config', with mock.patch.object(drvr, '_get_volume_config',
return_value=conf): return_value=conf):
parser = etree.XMLParser(remove_blank_text=True) parser = etree.XMLParser(remove_blank_text=True)
xml_doc = etree.fromstring(initial_xml, parser) xml_doc = etree.fromstring(initial_xml, parser)
config = drvr._update_volume_xml(xml_doc, config = drvr._update_volume_xml(xml_doc, [bdmi])
volume_xml['volume'])
xml_doc = etree.fromstring(target_xml, parser) xml_doc = etree.fromstring(target_xml, parser)
self.assertEqual(etree.tostring(xml_doc), etree.tostring(config)) self.assertEqual(etree.tostring(xml_doc), etree.tostring(config))
@ -6652,39 +6656,38 @@ class LibvirtConnTestCase(test.NoDBTestCase):
'abc.12345.opst-lun-X') 'abc.12345.opst-lun-X')
target_xml = etree.tostring(etree.fromstring(target_xml)) target_xml = etree.tostring(etree.fromstring(target_xml))
serial = "58a84f6d-3f0c-4e19-a0af-eb657b790657" serial = "58a84f6d-3f0c-4e19-a0af-eb657b790657"
volume_xml = {'volume': {}} connection_info = {
volume_xml['volume'][serial] = {'connection_info': {}, 'disk_info': {}} u'driver_volume_type': u'iscsi',
volume_xml['volume'][serial]['connection_info'] = \
{u'driver_volume_type': u'iscsi',
'serial': u'58a84f6d-3f0c-4e19-a0af-eb657b790657', 'serial': u'58a84f6d-3f0c-4e19-a0af-eb657b790657',
u'data': {u'access_mode': u'rw', u'target_discovered': False, u'data': {
u'access_mode': u'rw', u'target_discovered': False,
u'target_iqn': u'ip-1.2.3.4:3260-iqn.cde.67890.opst-lun-Z', u'target_iqn': u'ip-1.2.3.4:3260-iqn.cde.67890.opst-lun-Z',
u'volume_id': u'58a84f6d-3f0c-4e19-a0af-eb657b790657', u'volume_id': u'58a84f6d-3f0c-4e19-a0af-eb657b790657',
'device_path': u'device_path':
u'/dev/disk/by-path/ip-1.2.3.4:3260-iqn.cde.67890.opst-lun-Z'}} u'/dev/disk/by-path/ip-1.2.3.4:3260-iqn.cde.67890.opst-lun-Z',
volume_xml['volume'][serial]['disk_info'] = {'bus': u'virtio', },
'type': u'disk', }
'dev': u'vdb'} bdmi = objects.LibvirtLiveMigrateBDMInfo(serial=serial,
bus='virtio',
connection_info = volume_xml['volume'][serial]['connection_info'] dev='vdb',
disk_info = volume_xml['volume'][serial]['disk_info'] type='disk')
bdmi.connection_info = connection_info
conf = vconfig.LibvirtConfigGuestDisk() conf = vconfig.LibvirtConfigGuestDisk()
conf.source_device = disk_info['type'] conf.source_device = bdmi.type
conf.driver_name = "qemu" conf.driver_name = "qemu"
conf.driver_format = "raw" conf.driver_format = "raw"
conf.driver_cache = "none" conf.driver_cache = "none"
conf.target_dev = disk_info['dev'] conf.target_dev = bdmi.dev
conf.target_bus = disk_info['bus'] conf.target_bus = bdmi.bus
conf.serial = connection_info.get('serial') conf.serial = bdmi.connection_info.get('serial')
conf.source_type = "block" conf.source_type = "block"
conf.source_path = connection_info['data'].get('device_path') conf.source_path = bdmi.connection_info['data'].get('device_path')
with mock.patch.object(drvr, '_get_volume_config', with mock.patch.object(drvr, '_get_volume_config',
return_value=conf): return_value=conf):
xml_doc = etree.fromstring(initial_xml) xml_doc = etree.fromstring(initial_xml)
config = drvr._update_volume_xml(xml_doc, config = drvr._update_volume_xml(xml_doc, [bdmi])
volume_xml['volume'])
self.assertEqual(target_xml, etree.tostring(config)) self.assertEqual(target_xml, etree.tostring(config))
def test_update_volume_xml_no_connection_info(self): def test_update_volume_xml_no_connection_info(self):
@ -6699,14 +6702,17 @@ class LibvirtConnTestCase(test.NoDBTestCase):
'abc.12345.opst-lun-X') 'abc.12345.opst-lun-X')
target_xml = etree.tostring(etree.fromstring(target_xml)) target_xml = etree.tostring(etree.fromstring(target_xml))
serial = "58a84f6d-3f0c-4e19-a0af-eb657b790657" serial = "58a84f6d-3f0c-4e19-a0af-eb657b790657"
volume_xml = {'volume': {}} bdmi = objects.LibvirtLiveMigrateBDMInfo(serial=serial,
volume_xml['volume'][serial] = {'info1': {}, 'info2': {}} dev='vdb',
type='disk',
bus='scsi',
format='qcow')
bdmi.connection_info = {}
conf = vconfig.LibvirtConfigGuestDisk() conf = vconfig.LibvirtConfigGuestDisk()
with mock.patch.object(drvr, '_get_volume_config', with mock.patch.object(drvr, '_get_volume_config',
return_value=conf): return_value=conf):
xml_doc = etree.fromstring(initial_xml) xml_doc = etree.fromstring(initial_xml)
config = drvr._update_volume_xml(xml_doc, config = drvr._update_volume_xml(xml_doc, [bdmi])
volume_xml['volume'])
self.assertEqual(target_xml, etree.tostring(config)) self.assertEqual(target_xml, etree.tostring(config))
@mock.patch.object(fakelibvirt.virDomain, "migrateToURI2") @mock.patch.object(fakelibvirt.virDomain, "migrateToURI2")
@ -6735,10 +6741,11 @@ class LibvirtConnTestCase(test.NoDBTestCase):
# start test # start test
bandwidth = CONF.libvirt.live_migration_bandwidth bandwidth = CONF.libvirt.live_migration_bandwidth
migrate_data = {'pre_live_migration_result': migrate_data = objects.LibvirtLiveMigrateData(
{'graphics_listen_addrs': graphics_listen_addr_vnc='10.0.0.1',
{'vnc': '10.0.0.1', 'spice': '10.0.0.2'}, graphics_listen_addr_spice='10.0.0.2',
'serial_listen_addr': '9.0.0.12'}} serial_listen_addr='9.0.0.12',
bdms=[])
dom = fakelibvirt.virDomain dom = fakelibvirt.virDomain
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
self.assertRaises(fakelibvirt.libvirtError, self.assertRaises(fakelibvirt.libvirtError,
@ -6759,12 +6766,14 @@ class LibvirtConnTestCase(test.NoDBTestCase):
CONF.set_override("enabled", True, "serial_console") CONF.set_override("enabled", True, "serial_console")
dom = fakelibvirt.virDomain dom = fakelibvirt.virDomain
migrate_data = objects.LibvirtLiveMigrateData(
serial_listen_addr='')
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
self.assertRaises(exception.MigrationError, self.assertRaises(exception.MigrationError,
drvr._live_migration_operation, drvr._live_migration_operation,
self.context, instance_ref, 'dest', self.context, instance_ref, 'dest',
False, None, dom) False, migrate_data, dom)
def test_live_migration_fails_with_invalid_live_migration_flag(self): def test_live_migration_fails_with_invalid_live_migration_flag(self):
self.flags(live_migration_flag="VIR_MIGRATE_UNDEFINE_SOURCE, " self.flags(live_migration_flag="VIR_MIGRATE_UNDEFINE_SOURCE, "
@ -6802,9 +6811,11 @@ class LibvirtConnTestCase(test.NoDBTestCase):
fakelibvirt.libvirtError("ERR")) fakelibvirt.libvirtError("ERR"))
# start test # start test
migrate_data = {'pre_live_migration_result': migrate_data = objects.LibvirtLiveMigrateData(
{'graphics_listen_addrs': graphics_listen_addr_vnc='0.0.0.0',
{'vnc': '0.0.0.0', 'spice': '0.0.0.0'}}} graphics_listen_addr_spice='0.0.0.0',
serial_listen_addr='127.0.0.1',
bdms=[])
self.mox.ReplayAll() self.mox.ReplayAll()
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
self.assertRaises(fakelibvirt.libvirtError, self.assertRaises(fakelibvirt.libvirtError,
@ -6831,7 +6842,9 @@ class LibvirtConnTestCase(test.NoDBTestCase):
fakelibvirt.libvirtError("ERR")) fakelibvirt.libvirtError("ERR"))
# start test # start test
migrate_data = {} migrate_data = objects.LibvirtLiveMigrateData(
serial_listen_addr='',
bdms=[])
self.mox.ReplayAll() self.mox.ReplayAll()
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
self.assertRaises(fakelibvirt.libvirtError, self.assertRaises(fakelibvirt.libvirtError,
@ -6855,9 +6868,10 @@ class LibvirtConnTestCase(test.NoDBTestCase):
self.mox.StubOutWithMock(vdmock, "migrateToURI") self.mox.StubOutWithMock(vdmock, "migrateToURI")
# start test # start test
migrate_data = {'pre_live_migration_result': migrate_data = objects.LibvirtLiveMigrateData(
{'graphics_listen_addrs': graphics_listen_addr_vnc='1.2.3.4',
{'vnc': '1.2.3.4', 'spice': '1.2.3.4'}}} graphics_listen_addr_spice='1.2.3.4',
serial_listen_addr='127.0.0.1')
self.mox.ReplayAll() self.mox.ReplayAll()
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
self.assertRaises(exception.MigrationError, self.assertRaises(exception.MigrationError,
@ -6897,9 +6911,11 @@ class LibvirtConnTestCase(test.NoDBTestCase):
fakelibvirt.libvirtError('ERR')) fakelibvirt.libvirtError('ERR'))
# start test # start test
migrate_data = {'pre_live_migration_result': migrate_data = objects.LibvirtLiveMigrateData(
{'graphics_listen_addrs': graphics_listen_addr_vnc='127.0.0.1',
{'vnc': '127.0.0.1', 'spice': '127.0.0.1'}}} graphics_listen_addr_spice='127.0.0.1',
serial_listen_addr='127.0.0.1',
bdms=[])
self.mox.ReplayAll() self.mox.ReplayAll()
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
self.assertRaises(fakelibvirt.libvirtError, self.assertRaises(fakelibvirt.libvirtError,
@ -6940,8 +6956,11 @@ class LibvirtConnTestCase(test.NoDBTestCase):
_bandwidth).AndRaise(test.TestingException('oops')) _bandwidth).AndRaise(test.TestingException('oops'))
graphics_listen_addrs = {'vnc': '0.0.0.0', 'spice': '127.0.0.1'} graphics_listen_addrs = {'vnc': '0.0.0.0', 'spice': '127.0.0.1'}
migrate_data = {'pre_live_migration_result': migrate_data = objects.LibvirtLiveMigrateData(
{'graphics_listen_addrs': graphics_listen_addrs}} graphics_listen_addr_vnc='0.0.0.0',
graphics_listen_addr_spice='127.0.0.1',
serial_listen_addr='127.0.0.1',
bdms=[])
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
self.mox.StubOutWithMock( self.mox.StubOutWithMock(
@ -6972,7 +6991,9 @@ class LibvirtConnTestCase(test.NoDBTestCase):
mock_get_instance_path.return_value = fake_instance_path mock_get_instance_path.return_value = fake_instance_path
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
migrate_data = {'is_shared_instance_path': False} migrate_data = objects.LibvirtLiveMigrateData(
is_shared_instance_path=False,
instance_relative_path=False)
self.assertRaises(exception.Invalid, self.assertRaises(exception.Invalid,
drvr.rollback_live_migration_at_destination, drvr.rollback_live_migration_at_destination,
"context", "instance", [], None, True, migrate_data) "context", "instance", [], None, True, migrate_data)
@ -6990,7 +7011,9 @@ class LibvirtConnTestCase(test.NoDBTestCase):
): ):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
migrate_data = {'is_shared_instance_path': True} migrate_data = objects.LibvirtLiveMigrateData(
is_shared_instance_path=True,
instance_relative_path=False)
drvr.rollback_live_migration_at_destination("context", "instance", [], drvr.rollback_live_migration_at_destination("context", "instance", [],
None, True, migrate_data) None, True, migrate_data)
mock_destroy.assert_called_once_with("context", "instance", [], mock_destroy.assert_called_once_with("context", "instance", [],

View File

@ -3536,16 +3536,16 @@ class XenAPILiveMigrateTestCase(stubs.XenAPITestBaseNoDB):
self.stubs.Set(self.conn._vmops, "_make_plugin_call", self.stubs.Set(self.conn._vmops, "_make_plugin_call",
fake_make_plugin_call) fake_make_plugin_call)
dest_check_data = {'block_migration': True, dest_check_data = objects.XenapiLiveMigrateData(
'is_volume_backed': True, block_migration=True,
'migrate_data': { is_volume_backed=True,
'destination_sr_ref': None, destination_sr_ref=None,
'migrate_send_data': None migrate_send_data=None)
}}
result = self.conn.check_can_live_migrate_source(self.context, result = self.conn.check_can_live_migrate_source(self.context,
{'host': 'host'}, {'host': 'host'},
dest_check_data) dest_check_data)
self.assertEqual(dest_check_data, result.to_legacy_dict()) self.assertEqual(dest_check_data.to_legacy_dict(),
result.to_legacy_dict())
def test_check_can_live_migrate_source_with_block_iscsi_fails(self): def test_check_can_live_migrate_source_with_block_iscsi_fails(self):
stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests) stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
@ -3676,8 +3676,9 @@ class XenAPILiveMigrateTestCase(stubs.XenAPITestBaseNoDB):
post_method.called = True post_method.called = True
# pass block_migration = True and migrate data # pass block_migration = True and migrate data
migrate_data = {"destination_sr_ref": "foo", migrate_data = objects.XenapiLiveMigrateData(
"migrate_send_data": "bar"} destination_sr_ref="foo",
migrate_send_data={"bar": "baz"})
self.conn.live_migration(self.conn, None, None, post_method, None, self.conn.live_migration(self.conn, None, None, post_method, None,
True, migrate_data) True, migrate_data)
self.assertTrue(post_method.called, "post_method.called") self.assertTrue(post_method.called, "post_method.called")
@ -3702,8 +3703,9 @@ class XenAPILiveMigrateTestCase(stubs.XenAPITestBaseNoDB):
block_migration, migrate_data): block_migration, migrate_data):
post_method.called = True post_method.called = True
migrate_data = {"destination_sr_ref": "foo", migrate_data = objects.XenapiLiveMigrateData(
"migrate_send_data": "bar"} destination_sr_ref="foo",
migrate_send_data={"bar": "baz"})
self.conn.live_migration(self.conn, None, None, post_method, None, self.conn.live_migration(self.conn, None, None, post_method, None,
True, migrate_data) True, migrate_data)
@ -3736,7 +3738,9 @@ class XenAPILiveMigrateTestCase(stubs.XenAPITestBaseNoDB):
block_migration): block_migration):
recover_method.called = True recover_method.called = True
# pass block_migration = True and migrate data # pass block_migration = True and migrate data
migrate_data = dict(destination_sr_ref='foo', migrate_send_data='bar') migrate_data = objects.XenapiLiveMigrateData(
destination_sr_ref='foo',
migrate_send_data={'bar': 'baz'})
self.assertRaises(exception.MigrationError, self.assertRaises(exception.MigrationError,
self.conn.live_migration, self.conn, self.conn.live_migration, self.conn,
None, None, None, recover_method, True, migrate_data) None, None, None, recover_method, True, migrate_data)
@ -3749,7 +3753,7 @@ class XenAPILiveMigrateTestCase(stubs.XenAPITestBaseNoDB):
class Session(xenapi_fake.SessionBase): class Session(xenapi_fake.SessionBase):
def VM_migrate_send(self_, session, vmref, migrate_data, islive, def VM_migrate_send(self_, session, vmref, migrate_data, islive,
vdi_map, vif_map, options): vdi_map, vif_map, options):
self.assertEqual('SOMEDATA', migrate_data) self.assertEqual({'SOMEDATA': 'SOMEVAL'}, migrate_data)
self.assertEqual(fake_vdi_map, vdi_map) self.assertEqual(fake_vdi_map, vdi_map)
stubs.stubout_session(self.stubs, Session) stubs.stubout_session(self.stubs, Session)
@ -3767,12 +3771,14 @@ class XenAPILiveMigrateTestCase(stubs.XenAPITestBaseNoDB):
def dummy_callback(*args, **kwargs): def dummy_callback(*args, **kwargs):
pass pass
migrate_data = objects.XenapiLiveMigrateData(
migrate_send_data={'SOMEDATA': 'SOMEVAL'},
destination_sr_ref='TARGET_SR_OPAQUE_REF')
conn.live_migration( conn.live_migration(
self.context, instance=dict(name='ignore'), dest=None, self.context, instance=dict(name='ignore'), dest=None,
post_method=dummy_callback, recover_method=dummy_callback, post_method=dummy_callback, recover_method=dummy_callback,
block_migration="SOMEDATA", block_migration="SOMEDATA",
migrate_data=dict(migrate_send_data='SOMEDATA', migrate_data=migrate_data)
destination_sr_ref="TARGET_SR_OPAQUE_REF"))
def test_live_migrate_pool_migration_xapi_call_parameters(self): def test_live_migrate_pool_migration_xapi_call_parameters(self):
@ -3795,10 +3801,13 @@ class XenAPILiveMigrateTestCase(stubs.XenAPITestBaseNoDB):
def dummy_callback(*args, **kwargs): def dummy_callback(*args, **kwargs):
pass pass
migrate_data = objects.XenapiLiveMigrateData(
migrate_send_data={'foo': 'bar'},
destination_sr_ref='foo')
self.assertRaises(IOError, conn.live_migration, self.assertRaises(IOError, conn.live_migration,
self.context, instance=dict(name='ignore'), dest=None, self.context, instance=dict(name='ignore'), dest=None,
post_method=dummy_callback, recover_method=dummy_callback, post_method=dummy_callback, recover_method=dummy_callback,
block_migration=False, migrate_data={}) block_migration=False, migrate_data=migrate_data)
def test_generate_vdi_map(self): def test_generate_vdi_map(self):
stubs.stubout_session(self.stubs, xenapi_fake.SessionBase) stubs.stubout_session(self.stubs, xenapi_fake.SessionBase)

View File

@ -5559,11 +5559,12 @@ class LibvirtDriver(driver.ComputeDriver):
post_method, recover_method, block_migration, post_method, recover_method, block_migration,
migrate_data) migrate_data)
def _update_xml(self, xml_str, volume, listen_addrs, serial_listen_addr): def _update_xml(self, xml_str, migrate_bdm_info, listen_addrs,
serial_listen_addr):
xml_doc = etree.fromstring(xml_str) xml_doc = etree.fromstring(xml_str)
if volume: if migrate_bdm_info:
xml_doc = self._update_volume_xml(xml_doc, volume) xml_doc = self._update_volume_xml(xml_doc, migrate_bdm_info)
if listen_addrs: if listen_addrs:
xml_doc = self._update_graphics_xml(xml_doc, listen_addrs) xml_doc = self._update_graphics_xml(xml_doc, listen_addrs)
else: else:
@ -5589,24 +5590,23 @@ class LibvirtDriver(driver.ComputeDriver):
return xml_doc return xml_doc
def _update_volume_xml(self, xml_doc, volume): def _update_volume_xml(self, xml_doc, migrate_bdm_info):
"""Update XML using device information of destination host.""" """Update XML using device information of destination host."""
# Update volume xml # Update volume xml
parser = etree.XMLParser(remove_blank_text=True) parser = etree.XMLParser(remove_blank_text=True)
disk_nodes = xml_doc.findall('./devices/disk') disk_nodes = xml_doc.findall('./devices/disk')
bdm_info_by_serial = {x.serial: x for x in migrate_bdm_info}
for pos, disk_dev in enumerate(disk_nodes): for pos, disk_dev in enumerate(disk_nodes):
serial_source = disk_dev.findtext('serial') serial_source = disk_dev.findtext('serial')
if serial_source is None or volume.get(serial_source) is None: bdm_info = bdm_info_by_serial.get(serial_source)
if (serial_source is None or
not bdm_info or not bdm_info.connection_info or
serial_source not in bdm_info_by_serial):
continue continue
if ('connection_info' not in volume[serial_source] or
'disk_info' not in volume[serial_source]):
continue
conf = self._get_volume_config( conf = self._get_volume_config(
volume[serial_source]['connection_info'], bdm_info.connection_info, bdm_info.as_disk_info())
volume[serial_source]['disk_info'])
xml_doc2 = etree.XML(conf.to_xml(), parser) xml_doc2 = etree.XML(conf.to_xml(), parser)
serial_dest = xml_doc2.findtext('serial') serial_dest = xml_doc2.findtext('serial')
@ -5663,9 +5663,9 @@ class LibvirtDriver(driver.ComputeDriver):
' the local address (127.0.0.1 or ::1).') ' the local address (127.0.0.1 or ::1).')
raise exception.MigrationError(reason=msg) raise exception.MigrationError(reason=msg)
if listen_addrs is not None: if listen_addrs:
dest_local_vnc = listen_addrs['vnc'] in LOCAL_ADDRS dest_local_vnc = listen_addrs.get('vnc') in LOCAL_ADDRS
dest_local_spice = listen_addrs['spice'] in LOCAL_ADDRS dest_local_spice = listen_addrs.get('spice') in LOCAL_ADDRS
if ((CONF.vnc.enabled and not dest_local_vnc) or if ((CONF.vnc.enabled and not dest_local_vnc) or
(CONF.spice.enabled and not dest_local_spice)): (CONF.spice.enabled and not dest_local_spice)):
@ -5730,18 +5730,20 @@ class LibvirtDriver(driver.ComputeDriver):
flagvals = [getflag(x.strip()) for x in flaglist] flagvals = [getflag(x.strip()) for x in flaglist]
logical_sum = six.moves.reduce(lambda x, y: x | y, flagvals) logical_sum = six.moves.reduce(lambda x, y: x | y, flagvals)
pre_live_migrate_data = (migrate_data or {}).get( listen_addrs = {}
'pre_live_migration_result', {}) if 'graphics_listen_addr_vnc' in migrate_data:
listen_addrs = pre_live_migrate_data.get('graphics_listen_addrs') listen_addrs['vnc'] = str(
volume = pre_live_migrate_data.get('volume') migrate_data.graphics_listen_addr_vnc)
serial_listen_addr = pre_live_migrate_data.get( if 'graphics_listen_addr_spice' in migrate_data:
'serial_listen_addr') listen_addrs['spice'] = str(
migrate_data.graphics_listen_addr_spice)
serial_listen_addr = migrate_data.serial_listen_addr
migratable_flag = getattr(libvirt, 'VIR_DOMAIN_XML_MIGRATABLE', migratable_flag = getattr(libvirt, 'VIR_DOMAIN_XML_MIGRATABLE',
None) None)
if (migratable_flag is None or if (migratable_flag is None or (
(listen_addrs is None and not volume)): not listen_addrs and not migrate_data.bdms)):
# TODO(alexs-h): These checks could be moved to the # TODO(alexs-h): These checks could be moved to the
# check_can_live_migrate_destination/source phase # check_can_live_migrate_destination/source phase
self._check_graphics_addresses_can_live_migrate(listen_addrs) self._check_graphics_addresses_can_live_migrate(listen_addrs)
@ -5753,7 +5755,7 @@ class LibvirtDriver(driver.ComputeDriver):
else: else:
old_xml_str = guest.get_xml_desc(dump_migratable=True) old_xml_str = guest.get_xml_desc(dump_migratable=True)
new_xml_str = self._update_xml(old_xml_str, new_xml_str = self._update_xml(old_xml_str,
volume, migrate_data.bdms,
listen_addrs, listen_addrs,
serial_listen_addr) serial_listen_addr)
try: try:
@ -6270,18 +6272,11 @@ class LibvirtDriver(driver.ComputeDriver):
# NOTE(gcb): Failed block live migration may leave instance # NOTE(gcb): Failed block live migration may leave instance
# directory at destination node, ensure it is always deleted. # directory at destination node, ensure it is always deleted.
is_shared_instance_path = True is_shared_instance_path = True
instance_relative_path = None
if migrate_data: if migrate_data:
is_shared_instance_path = migrate_data.get( is_shared_instance_path = migrate_data.is_shared_instance_path
'is_shared_instance_path', True)
instance_relative_path = migrate_data.get(
'instance_relative_path')
mdo = objects.LibvirtLiveMigrateData()
if instance_relative_path:
mdo.instance_relative_path = instance_relative_path
if not is_shared_instance_path: if not is_shared_instance_path:
instance_dir = libvirt_utils.get_instance_path_at_destination( instance_dir = libvirt_utils.get_instance_path_at_destination(
instance, mdo) instance, migrate_data)
if os.path.exists(instance_dir): if os.path.exists(instance_dir):
shutil.rmtree(instance_dir) shutil.rmtree(instance_dir)

View File

@ -2198,13 +2198,9 @@ class VMOps(object):
if ('block_migration' in dest_check_data and if ('block_migration' in dest_check_data and
dest_check_data.block_migration): dest_check_data.block_migration):
vm_ref = self._get_vm_opaque_ref(instance_ref) vm_ref = self._get_vm_opaque_ref(instance_ref)
migrate_data = {
'destination_sr_ref': dest_check_data.destination_sr_ref,
'migrate_send_data': dest_check_data.migrate_send_data,
}
try: try:
self._call_live_migrate_command( self._call_live_migrate_command(
"VM.assert_can_migrate", vm_ref, migrate_data) "VM.assert_can_migrate", vm_ref, dest_check_data)
except self._session.XenAPI.Failure as exc: except self._session.XenAPI.Failure as exc:
reason = exc.details[0] reason = exc.details[0]
msg = _('assert_can_migrate failed because: %s') % reason msg = _('assert_can_migrate failed because: %s') % reason
@ -2288,8 +2284,8 @@ class VMOps(object):
def _call_live_migrate_command(self, command_name, vm_ref, migrate_data): def _call_live_migrate_command(self, command_name, vm_ref, migrate_data):
"""unpack xapi specific parameters, and call a live migrate command.""" """unpack xapi specific parameters, and call a live migrate command."""
destination_sr_ref = migrate_data['destination_sr_ref'] destination_sr_ref = migrate_data.destination_sr_ref
migrate_send_data = migrate_data['migrate_send_data'] migrate_send_data = migrate_data.migrate_send_data
vdi_map = self._generate_vdi_map(destination_sr_ref, vm_ref) vdi_map = self._generate_vdi_map(destination_sr_ref, vm_ref)
@ -2331,8 +2327,8 @@ class VMOps(object):
if migrate_data is not None: if migrate_data is not None:
(kernel, ramdisk) = vm_utils.lookup_kernel_ramdisk( (kernel, ramdisk) = vm_utils.lookup_kernel_ramdisk(
self._session, vm_ref) self._session, vm_ref)
migrate_data['kernel-file'] = kernel migrate_data.kernel_file = kernel
migrate_data['ramdisk-file'] = ramdisk migrate_data.ramdisk_file = ramdisk
if block_migration: if block_migration:
if not migrate_data: if not migrate_data:
@ -2366,8 +2362,8 @@ class VMOps(object):
def post_live_migration(self, context, instance, migrate_data=None): def post_live_migration(self, context, instance, migrate_data=None):
if migrate_data is not None: if migrate_data is not None:
vm_utils.destroy_kernel_ramdisk(self._session, instance, vm_utils.destroy_kernel_ramdisk(self._session, instance,
migrate_data.get('kernel-file'), migrate_data.kernel_file,
migrate_data.get('ramdisk-file')) migrate_data.ramdisk_file)
def post_live_migration_at_destination(self, context, instance, def post_live_migration_at_destination(self, context, instance,
network_info, block_migration, network_info, block_migration,