Rediscover hdisk if connection info refreshed

Although the UDID for a VSCSI attached volume is saved in the bdm
during attach, it can be lost if the connection information is
'refreshed' by the compute manager.  This fix rediscovers the hdisk
during detach if we cannot look it up via the UDID. One scenario
where the connection info is refreshed is live migration.

Change-Id: I13846c494d72d57e47082d4d0fb2a286309aa0f1
This commit is contained in:
Kyle L. Henderson 2015-09-02 14:22:18 -05:00
parent 0b79b60c32
commit b380b0e445
2 changed files with 59 additions and 11 deletions

View File

@ -68,10 +68,16 @@ class BaseVSCSITest(test.TestCase):
@mock.patch('pypowervm.wrappers.virtual_io_server.VIOS.getter')
@mock.patch('nova_powervm.virt.powervm.vm.get_pvm_uuid')
def init_vol_adpt(mock_pvm_uuid, mock_getter):
con_info = {'data': {'initiator_target_map': {p_wwpn1: ['t1'],
p_wwpn2: ['t2',
't3']},
'target_lun': '1', 'volume_id': 'id'}}
con_info = {
'data': {
'initiator_target_map': {
p_wwpn1: ['t1'],
p_wwpn2: ['t2', 't3']
},
'target_lun': '1',
'volume_id': 'id'
},
}
mock_inst = mock.MagicMock()
mock_pvm_uuid.return_value = '1234'
@ -189,6 +195,7 @@ class TestVSCSIAdapter(BaseVSCSITest):
# The mock return values
mock_hdisk_from_uuid.return_value = 'device_name'
mock_get_vm_id.return_value = 'partition_id'
self.vol_drv._set_udid('UDIDIT!')
def validate_remove_maps(vios_w, vm_uuid, match_func):
self.assertIsInstance(vios_w, pvm_vios.VIOS)
@ -216,6 +223,7 @@ class TestVSCSIAdapter(BaseVSCSITest):
mock_remove_maps.return_value = None
mock_hdisk_from_uuid.return_value = 'device_name'
mock_get_vm_id.return_value = 'partition_id'
self.vol_drv._set_udid('UDIDIT!')
# Run the method
self.vol_drv.disconnect_volume()
@ -225,6 +233,38 @@ class TestVSCSIAdapter(BaseVSCSITest):
self.assertEqual(0, self.ft_fx.patchers['update'].mock.call_count)
self.assertEqual(1, len(self.vol_drv._vioses_modified))
@mock.patch('pypowervm.tasks.hdisk.remove_hdisk')
@mock.patch('pypowervm.wrappers.virtual_io_server.VIOS.hdisk_from_uuid')
@mock.patch('pypowervm.tasks.scsi_mapper.remove_maps')
@mock.patch('nova_powervm.virt.powervm.vm.get_vm_id')
def test_disconnect_volume_no_udid(
self, mock_get_vm_id, mock_remove_maps, mock_hdisk_from_uuid,
mock_remove_hdisk):
# The mock return values
mock_hdisk_from_uuid.return_value = 'device_name'
mock_get_vm_id.return_value = 'partition_id'
def validate_remove_maps(vios_w, vm_uuid, match_func):
self.assertIsInstance(vios_w, pvm_vios.VIOS)
self.assertEqual('partition_id', vm_uuid)
return 'removed'
mock_remove_maps.side_effect = validate_remove_maps
with mock.patch.object(
self.vol_drv, '_discover_volume_on_vios',
return_value=('status', 'dev_name', 'udidit')):
# Run the method
self.vol_drv.disconnect_volume()
# As initialized above, remove_maps returns True to trigger update.
self.assertEqual(1, mock_remove_maps.call_count)
self.assertEqual(1, self.ft_fx.patchers['update'].mock.call_count)
mock_remove_hdisk.assert_called_once_with(
self.adpt, mock.ANY, 'dev_name', self.vios_uuid)
self.assertListEqual([self.vios_uuid], self.vol_drv._vioses_modified)
@mock.patch('pypowervm.wrappers.virtual_io_server.VIOS.hdisk_from_uuid')
@mock.patch('pypowervm.tasks.scsi_mapper.remove_maps')
def test_disconnect_volume_no_valid_vio(self, mock_remove_maps,

View File

@ -250,16 +250,22 @@ class VscsiVolumeAdapter(v_driver.FibreChannelVolumeAdapter):
"""
LOG.debug("Disconnect volume %(vol)s from vios uuid %(uuid)s",
dict(vol=volume_id, uuid=vios_w.uuid))
volume_udid = None
udid, device_name = None, None
try:
volume_udid = self._get_udid()
device_name = vios_w.hdisk_from_uuid(volume_udid)
udid = self._get_udid()
if not udid:
# We lost our bdm data. We'll need to discover it.
status, device_name, udid = self._discover_volume_on_vios(
vios_w, volume_id)
if udid and not device_name:
device_name = vios_w.hdisk_from_uuid(udid)
if not device_name:
LOG.warn(_LW("Disconnect Volume: No mapped device found on "
"Virtual I/O Server %(vios)s for volume "
"%(volume_id)s. Volume UDID: %(volume_uid)s"),
{'volume_uid': volume_udid, 'volume_id': volume_id,
{'volume_uid': udid, 'volume_id': volume_id,
'vios': vios_w.name})
return False
@ -267,7 +273,7 @@ class VscsiVolumeAdapter(v_driver.FibreChannelVolumeAdapter):
LOG.warn(_LW("Disconnect Volume: Failed to find disk on Virtual "
"I/O Server %(vios_name)s for volume %(volume_id)s. "
"Volume UDID: %(volume_uid)s. Error: %(error)s"),
{'error': e, 'volume_uid': volume_udid,
{'error': e, 'volume_uid': udid,
'volume_id': volume_id, 'vios_name': vios_w.name})
return False
@ -275,7 +281,7 @@ class VscsiVolumeAdapter(v_driver.FibreChannelVolumeAdapter):
LOG.info(_LI("Disconnect Volume: Discovered the device %(hdisk)s on "
"Virtual I/O Server %(vios_name)s for volume "
"%(volume_id)s. Volume UDID: %(volume_uid)s."),
{'volume_uid': volume_udid, 'volume_id': volume_id,
{'volume_uid': udid, 'volume_id': volume_id,
'vios_name': vios_w.name, 'hdisk': device_name})
# Add the action to remove the mapping when the stg_ftsk is run.
@ -405,6 +411,8 @@ class VscsiVolumeAdapter(v_driver.FibreChannelVolumeAdapter):
try:
return self.connection_info['data'][UDID_KEY]
except (KeyError, ValueError):
LOG.warn(_LW(u'Failed to retrieve device_id key from BDM for '
# It's common to lose our specific data in the BDM. The connection
# information can be 'refreshed' by operations like LPM and resize
LOG.info(_LI(u'Failed to retrieve device_id key from BDM for '
'volume id %s'), self.volume_id)
return None