iSCSI Live Migration Support

Implement the interfaces needed to support live migration.

Change-Id: I38cb9ccbae311e0e5edcef4a2d4464d45ef3db39
This commit is contained in:
Chhavi Agarwal 2018-05-10 08:11:58 -04:00
parent 8429cc6185
commit ba17efd947
2 changed files with 107 additions and 1 deletions

View File

@ -487,3 +487,82 @@ class TestISCSIAdapter(test_vol.TestVolumeAdapter):
self.vol_drv.connection_info['data'].pop('target_iqn')
props = self.vol_drv._get_iscsi_conn_props(vios_w, auth=False)
self.assertIsNone(props)
@mock.patch('nova_powervm.virt.powervm.volume.driver.PowerVMVolumeAdapter.'
'vios_uuids', new_callable=mock.PropertyMock)
@mock.patch('pypowervm.tasks.hdisk.discover_iscsi')
@mock.patch('pypowervm.tasks.storage.find_stale_lpars')
def test_pre_live_migration(self, mock_fsl, mock_discover,
mock_vios_uuids):
# The mock return values
vios_ids = ['1300C76F-9814-4A4D-B1F0-5B69352A7DEA',
'7DBBE705-E4C4-4458-8223-3EBE07015CA9']
mock_vios_uuids.return_value = vios_ids
mock_fsl.return_value = []
mock_discover.return_value = (
'devname', 'udid')
# Run the method
migrate_data = {}
self.vol_drv.pre_live_migration_on_destination(migrate_data)
volume_key = 'vscsi-' + self.serial
self.assertEqual(migrate_data, {volume_key: 'udid'})
# Test exception path
mock_discover.return_value = (
'devname', None)
# Run the method
self.assertRaises(p_exc.VolumePreMigrationFailed,
self.vol_drv.pre_live_migration_on_destination, {})
# Test when volume discover on a single vios
mock_discover.reset_mock()
mock_discover.side_effect = [('devname', 'udid'), ('devname', None)]
self.vol_drv.pre_live_migration_on_destination(migrate_data)
self.assertEqual(migrate_data, {volume_key: 'udid'})
self.assertEqual(2, mock_discover.call_count)
# Test with bad vios_uuid
mock_discover.reset_mock()
mock_vios_uuids.return_value = ['fake_vios']
self.assertRaises(p_exc.VolumePreMigrationFailed,
self.vol_drv.pre_live_migration_on_destination, {})
mock_discover.assert_not_called()
@mock.patch('nova_powervm.virt.powervm.volume.driver.PowerVMVolumeAdapter.'
'vios_uuids', new_callable=mock.PropertyMock)
def test_is_volume_on_vios(self, mock_vios_uuids):
# The mock return values
mock_vios_uuids.return_value = ['fake_vios1', 'fake_vios2']
with mock.patch.object(self.vol_drv,
'_discover_volume_on_vios') as mock_discover:
found, udid = self.vol_drv.is_volume_on_vios(self.feed[0])
mock_discover.assert_not_called()
self.assertFalse(found)
self.assertIsNone(udid)
mock_discover.reset_mock()
mock_discover.return_value = 'device1', 'udid1'
vios_ids = ['1300C76F-9814-4A4D-B1F0-5B69352A7DEA',
'7DBBE705-E4C4-4458-8223-3EBE07015CA9']
mock_vios_uuids.return_value = vios_ids
found, udid = self.vol_drv.is_volume_on_vios(self.feed[0])
mock_discover.assert_called_once_with(self.feed[0])
self.assertTrue(found)
self.assertEqual(udid, 'udid1')
mock_discover.reset_mock()
mock_discover.return_value = None, 'udid1'
found, udid = self.vol_drv.is_volume_on_vios(self.feed[0])
self.assertFalse(found)
self.assertEqual(udid, 'udid1')
mock_discover.reset_mock()
mock_discover.return_value = 'device1', None
found, udid = self.vol_drv.is_volume_on_vios(self.feed[0])
self.assertFalse(found)
self.assertIsNone(udid)

View File

@ -137,7 +137,32 @@ class IscsiVolumeAdapter(volume.VscsiVolumeAdapter,
information to the live_migration command, it
should be added to this dictionary.
"""
raise NotImplementedError()
# See the connect_volume for why this is a direct call instead of
# using the tx_mgr.feed
vios_wraps = pvm_vios.VIOS.get(self.adapter,
xag=[pvm_const.XAG.VIO_STOR])
volume_key = 'vscsi-' + self.volume_id
for vios_w in vios_wraps:
if vios_w.uuid not in self.vios_uuids:
continue
# Discover the volume on all VIOS's to trigger the
# device configuration, which in turn will discover the
# LUN associated with the volume. This needs to be
# attempted on all VIOS's to determine the VIOS's that
# will be servicing IO for this volume.
udid = self._discover_volume_on_vios(vios_w)[1]
if udid:
LOG.debug("Discovered volume udid %(udid)s on vios %(name)s",
dict(udid=udid, name=vios_w.name))
mig_data[volume_key] = udid
if volume_key not in mig_data:
LOG.debug("Failed to discover the volume")
ex_args = dict(volume_id=self.volume_id,
instance_name=self.instance.name)
raise p_exc.VolumePreMigrationFailed(**ex_args)
def is_volume_on_vios(self, vios_w):
"""Returns whether or not the volume is on a VIOS.
@ -147,6 +172,8 @@ class IscsiVolumeAdapter(volume.VscsiVolumeAdapter,
otherwise.
:return: The udid of the device.
"""
if vios_w.uuid not in self.vios_uuids:
return False, None
device_name, udid = self._discover_volume_on_vios(vios_w)
return (device_name and udid) is not None, udid