Dell EMC SC: On None connector terminate_connection unmaps all
On terminate_connection if the connector is None the driver now detatches the volume from all mapped servers. It leaves connections to remote Storage Center's so things like replication and live volume continue. Change-Id: I205006a3ebab742883018d564e766031024eeb3d
This commit is contained in:
parent
f1f1ff45b9
commit
00e54d6049
|
@ -573,6 +573,90 @@ class DellSCSanFCDriverTestCase(test.TestCase):
|
|||
expected = (None, [], {})
|
||||
self.assertEqual(expected, ret)
|
||||
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'find_volume')
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'unmap_all')
|
||||
@mock.patch.object(storagecenter_fc.SCFCDriver,
|
||||
'_is_live_vol')
|
||||
def test_force_detach(self, mock_is_live_vol, mock_unmap_all,
|
||||
mock_find_volume, mock_close_connection,
|
||||
mock_open_connection, mock_init):
|
||||
mock_is_live_vol.return_value = False
|
||||
scvol = {'instandId': '12345.1'}
|
||||
mock_find_volume.return_value = scvol
|
||||
mock_unmap_all.return_value = True
|
||||
volume = {'id': fake.VOLUME_ID}
|
||||
res = self.driver.force_detach(volume)
|
||||
mock_unmap_all.assert_called_once_with(scvol)
|
||||
expected = {'driver_volume_type': 'fibre_channel',
|
||||
'data': {}}
|
||||
self.assertEqual(expected, res)
|
||||
mock_unmap_all.assert_called_once_with(scvol)
|
||||
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'find_volume')
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'unmap_all')
|
||||
@mock.patch.object(storagecenter_fc.SCFCDriver,
|
||||
'_is_live_vol')
|
||||
def test_force_detach_fail(self, mock_is_live_vol, mock_unmap_all,
|
||||
mock_find_volume, mock_close_connection,
|
||||
mock_open_connection, mock_init):
|
||||
mock_is_live_vol.return_value = False
|
||||
scvol = {'instandId': '12345.1'}
|
||||
mock_find_volume.return_value = scvol
|
||||
mock_unmap_all.return_value = False
|
||||
volume = {'id': fake.VOLUME_ID}
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.force_detach, volume)
|
||||
mock_unmap_all.assert_called_once_with(scvol)
|
||||
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'find_volume')
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'unmap_all')
|
||||
@mock.patch.object(storagecenter_fc.SCFCDriver,
|
||||
'_is_live_vol')
|
||||
@mock.patch.object(storagecenter_fc.SCFCDriver,
|
||||
'terminate_secondary')
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'get_live_volume')
|
||||
def test_force_detach_lv(self, mock_get_live_volume,
|
||||
mock_terminate_secondary, mock_is_live_vol,
|
||||
mock_unmap_all, mock_find_volume,
|
||||
mock_close_connection, mock_open_connection,
|
||||
mock_init):
|
||||
mock_is_live_vol.return_value = True
|
||||
scvol = {'instandId': '12345.1'}
|
||||
mock_find_volume.return_value = scvol
|
||||
sclivevol = {'instandId': '12345.1.0'}
|
||||
mock_get_live_volume.return_value = sclivevol
|
||||
mock_terminate_secondary.return_value = True
|
||||
volume = {'id': fake.VOLUME_ID}
|
||||
mock_unmap_all.return_value = True
|
||||
res = self.driver.force_detach(volume)
|
||||
mock_unmap_all.assert_called_once_with(scvol)
|
||||
expected = {'driver_volume_type': 'fibre_channel', 'data': {}}
|
||||
self.assertEqual(expected, res)
|
||||
self.assertEqual(1, mock_terminate_secondary.call_count)
|
||||
mock_unmap_all.assert_called_once_with(scvol)
|
||||
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'find_volume')
|
||||
@mock.patch.object(storagecenter_fc.SCFCDriver,
|
||||
'_is_live_vol')
|
||||
def test_force_detach_vol_not_found(self,
|
||||
mock_is_live_vol, mock_find_volume,
|
||||
mock_close_connection,
|
||||
mock_open_connection, mock_init):
|
||||
mock_is_live_vol.return_value = False
|
||||
mock_find_volume.return_value = None
|
||||
volume = {'id': fake.VOLUME_ID}
|
||||
res = self.driver.force_detach(volume)
|
||||
expected = {'driver_volume_type': 'fibre_channel', 'data': {}}
|
||||
self.assertEqual(expected, res)
|
||||
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'find_server',
|
||||
return_value=SCSERVER)
|
||||
|
@ -611,6 +695,16 @@ class DellSCSanFCDriverTestCase(test.TestCase):
|
|||
'data': {}}
|
||||
self.assertEqual(expected, res, 'Unexpected return data')
|
||||
|
||||
@mock.patch.object(storagecenter_fc.SCFCDriver,
|
||||
'force_detach')
|
||||
def test_terminate_connection_none_connector(self, mock_force_detach,
|
||||
mock_close_connection,
|
||||
mock_open_connection,
|
||||
mock_init):
|
||||
volume = {'id': fake.VOLUME_ID}
|
||||
self.driver.terminate_connection(volume, None)
|
||||
mock_force_detach.assert_called_once_with(volume)
|
||||
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'find_server',
|
||||
return_value=SCSERVER)
|
||||
|
|
|
@ -1325,6 +1325,87 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
|
|||
mock_api.unmap_volume.assert_called_once_with(self.VOLUME,
|
||||
self.SCSERVER)
|
||||
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'find_volume')
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'unmap_all')
|
||||
@mock.patch.object(storagecenter_iscsi.SCISCSIDriver,
|
||||
'_is_live_vol')
|
||||
def test_force_detach(self, mock_is_live_vol, mock_unmap_all,
|
||||
mock_find_volume, mock_close_connection,
|
||||
mock_open_connection, mock_init):
|
||||
mock_is_live_vol.return_value = False
|
||||
scvol = {'instandId': '12345.1'}
|
||||
mock_find_volume.return_value = scvol
|
||||
mock_unmap_all.return_value = True
|
||||
volume = {'id': fake.VOLUME_ID}
|
||||
res = self.driver.force_detach(volume)
|
||||
mock_unmap_all.assert_called_once_with(scvol)
|
||||
self.assertTrue(res)
|
||||
mock_unmap_all.assert_called_once_with(scvol)
|
||||
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'find_volume')
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'unmap_all')
|
||||
@mock.patch.object(storagecenter_iscsi.SCISCSIDriver,
|
||||
'_is_live_vol')
|
||||
def test_force_detach_fail(self, mock_is_live_vol, mock_unmap_all,
|
||||
mock_find_volume, mock_close_connection,
|
||||
mock_open_connection, mock_init):
|
||||
mock_is_live_vol.return_value = False
|
||||
scvol = {'instandId': '12345.1'}
|
||||
mock_find_volume.return_value = scvol
|
||||
mock_unmap_all.return_value = False
|
||||
volume = {'id': fake.VOLUME_ID}
|
||||
res = self.driver.force_detach(volume)
|
||||
mock_unmap_all.assert_called_once_with(scvol)
|
||||
self.assertFalse(res)
|
||||
mock_unmap_all.assert_called_once_with(scvol)
|
||||
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'find_volume')
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'unmap_all')
|
||||
@mock.patch.object(storagecenter_iscsi.SCISCSIDriver,
|
||||
'_is_live_vol')
|
||||
@mock.patch.object(storagecenter_iscsi.SCISCSIDriver,
|
||||
'terminate_secondary')
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'get_live_volume')
|
||||
def test_force_detach_lv(self, mock_get_live_volume,
|
||||
mock_terminate_secondary, mock_is_live_vol,
|
||||
mock_unmap_all, mock_find_volume,
|
||||
mock_close_connection, mock_open_connection,
|
||||
mock_init):
|
||||
mock_is_live_vol.return_value = True
|
||||
scvol = {'instandId': '12345.1'}
|
||||
mock_find_volume.return_value = scvol
|
||||
sclivevol = {'instandId': '12345.1.0'}
|
||||
mock_get_live_volume.return_value = sclivevol
|
||||
mock_terminate_secondary.return_value = True
|
||||
volume = {'id': fake.VOLUME_ID}
|
||||
mock_unmap_all.return_value = True
|
||||
res = self.driver.force_detach(volume)
|
||||
mock_unmap_all.assert_called_once_with(scvol)
|
||||
self.assertTrue(res)
|
||||
self.assertEqual(1, mock_terminate_secondary.call_count)
|
||||
mock_unmap_all.assert_called_once_with(scvol)
|
||||
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'find_volume')
|
||||
@mock.patch.object(storagecenter_iscsi.SCISCSIDriver,
|
||||
'_is_live_vol')
|
||||
def test_force_detach_vol_not_found(self,
|
||||
mock_is_live_vol, mock_find_volume,
|
||||
mock_close_connection,
|
||||
mock_open_connection, mock_init):
|
||||
mock_is_live_vol.return_value = False
|
||||
mock_find_volume.return_value = None
|
||||
volume = {'id': fake.VOLUME_ID}
|
||||
res = self.driver.force_detach(volume)
|
||||
self.assertFalse(res)
|
||||
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'find_server',
|
||||
return_value=SCSERVER)
|
||||
|
@ -1347,6 +1428,16 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
|
|||
mock_unmap_volume.assert_called_once_with(self.VOLUME, self.SCSERVER)
|
||||
self.assertIsNone(res, 'None expected')
|
||||
|
||||
@mock.patch.object(storagecenter_iscsi.SCISCSIDriver,
|
||||
'force_detach')
|
||||
def test_terminate_connection_no_connector(self, mock_force_detach,
|
||||
mock_close_connection,
|
||||
mock_open_connection,
|
||||
mock_init):
|
||||
volume = {'id': fake.VOLUME_ID}
|
||||
self.driver.terminate_connection(volume, None)
|
||||
mock_force_detach.assert_called_once_with(volume)
|
||||
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'find_server',
|
||||
return_value=SCSERVER)
|
||||
|
|
|
@ -4231,6 +4231,125 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||
self.assertFalse(mock_delete.called)
|
||||
self.assertTrue(res)
|
||||
|
||||
@mock.patch.object(storagecenter_api.HttpClient,
|
||||
'delete')
|
||||
@mock.patch.object(storagecenter_api.HttpClient,
|
||||
'get')
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'_find_mapping_profiles')
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'_get_json')
|
||||
def test_unmap_all(self, mock_get_json, mock_find_mapping_profiles,
|
||||
mock_get, mock_delete, mock_close_connection,
|
||||
mock_open_connection, mock_init):
|
||||
mock_delete.return_value = self.RESPONSE_200
|
||||
mock_get.return_value = self.RESPONSE_200
|
||||
mock_find_mapping_profiles.return_value = [
|
||||
{'instanceId': '12345.0.1',
|
||||
'server': {'instanceId': '12345.100', 'instanceName': 'Srv1'}},
|
||||
{'instanceId': '12345.0.2',
|
||||
'server': {'instanceId': '12345.101', 'instanceName': 'Srv2'}},
|
||||
{'instanceId': '12345.0.3',
|
||||
'server': {'instanceId': '12345.102', 'instanceName': 'Srv3'}},
|
||||
]
|
||||
# server, result pairs
|
||||
mock_get_json.side_effect = [
|
||||
{'instanceId': '12345.100', 'instanceName': 'Srv1',
|
||||
'type': 'Physical'},
|
||||
{'result': True},
|
||||
{'instanceId': '12345.101', 'instanceName': 'Srv2',
|
||||
'type': 'Physical'},
|
||||
{'result': True},
|
||||
{'instanceId': '12345.102', 'instanceName': 'Srv3',
|
||||
'type': 'Physical'},
|
||||
{'result': True}
|
||||
]
|
||||
vol = {'instanceId': '12345.0', 'name': 'vol1'}
|
||||
res = self.scapi.unmap_all(vol)
|
||||
# Success and 3 delete calls
|
||||
self.assertTrue(res)
|
||||
self.assertEqual(3, mock_delete.call_count)
|
||||
|
||||
@mock.patch.object(storagecenter_api.HttpClient,
|
||||
'delete')
|
||||
@mock.patch.object(storagecenter_api.HttpClient,
|
||||
'get')
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'_find_mapping_profiles')
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'_get_json')
|
||||
def test_unmap_all_with_remote(self, mock_get_json,
|
||||
mock_find_mapping_profiles, mock_get,
|
||||
mock_delete, mock_close_connection,
|
||||
mock_open_connection, mock_init):
|
||||
mock_delete.return_value = self.RESPONSE_200
|
||||
mock_get.return_value = self.RESPONSE_200
|
||||
mock_find_mapping_profiles.return_value = [
|
||||
{'instanceId': '12345.0.1',
|
||||
'server': {'instanceId': '12345.100', 'instanceName': 'Srv1'}},
|
||||
{'instanceId': '12345.0.2',
|
||||
'server': {'instanceId': '12345.101', 'instanceName': 'Srv2'}},
|
||||
{'instanceId': '12345.0.3',
|
||||
'server': {'instanceId': '12345.102', 'instanceName': 'Srv3'}},
|
||||
]
|
||||
# server, result pairs
|
||||
mock_get_json.side_effect = [
|
||||
{'instanceId': '12345.100', 'instanceName': 'Srv1',
|
||||
'type': 'Physical'},
|
||||
{'result': True},
|
||||
{'instanceId': '12345.101', 'instanceName': 'Srv2',
|
||||
'type': 'RemoteStorageCenter'},
|
||||
{'instanceId': '12345.102', 'instanceName': 'Srv3',
|
||||
'type': 'Physical'},
|
||||
{'result': True}
|
||||
]
|
||||
vol = {'instanceId': '12345.0', 'name': 'vol1'}
|
||||
res = self.scapi.unmap_all(vol)
|
||||
# Should succeed but call delete only twice
|
||||
self.assertTrue(res)
|
||||
self.assertEqual(2, mock_delete.call_count)
|
||||
|
||||
@mock.patch.object(storagecenter_api.HttpClient,
|
||||
'delete')
|
||||
@mock.patch.object(storagecenter_api.HttpClient,
|
||||
'get')
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'_find_mapping_profiles')
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'_get_json')
|
||||
def test_unmap_all_fail(self, mock_get_json, mock_find_mapping_profiles,
|
||||
mock_get, mock_delete, mock_close_connection,
|
||||
mock_open_connection, mock_init):
|
||||
mock_delete.return_value = self.RESPONSE_400
|
||||
mock_get.return_value = self.RESPONSE_200
|
||||
mock_find_mapping_profiles.return_value = [
|
||||
{'instanceId': '12345.0.1',
|
||||
'server': {'instanceId': '12345.100', 'instanceName': 'Srv1'}},
|
||||
{'instanceId': '12345.0.2',
|
||||
'server': {'instanceId': '12345.101', 'instanceName': 'Srv2'}},
|
||||
{'instanceId': '12345.0.3',
|
||||
'server': {'instanceId': '12345.102', 'instanceName': 'Srv3'}},
|
||||
]
|
||||
# server, result pairs
|
||||
mock_get_json.side_effect = [
|
||||
{'instanceId': '12345.100', 'instanceName': 'Srv1',
|
||||
'type': 'Physical'}
|
||||
]
|
||||
vol = {'instanceId': '12345.0', 'name': 'vol1'}
|
||||
res = self.scapi.unmap_all(vol)
|
||||
self.assertFalse(res)
|
||||
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'_find_mapping_profiles')
|
||||
def test_unmap_all_no_profiles(self, mock_find_mapping_profiles,
|
||||
mock_close_connection, mock_open_connection,
|
||||
mock_init):
|
||||
mock_find_mapping_profiles.return_value = []
|
||||
vol = {'instanceId': '12345.0', 'name': 'vol1'}
|
||||
res = self.scapi.unmap_all(vol)
|
||||
# Should exit with success.
|
||||
self.assertTrue(res)
|
||||
|
||||
@mock.patch.object(storagecenter_api.SCApi,
|
||||
'_get_json',
|
||||
return_value=[{'a': 1}, {'a': 2}])
|
||||
|
|
|
@ -1993,10 +1993,51 @@ class SCApi(object):
|
|||
return rtn
|
||||
|
||||
def unmap_all(self, scvolume):
|
||||
volumeid = self._get_id(scvolume)
|
||||
r = self.client.post('StorageCenter/ScVolume/%s/Unmap' % volumeid,
|
||||
{}, True)
|
||||
return self._check_result(r)
|
||||
"""Unmaps a volume from all connections except SCs.
|
||||
|
||||
:param scvolume: The SC Volume object.
|
||||
:return: Boolean
|
||||
"""
|
||||
rtn = True
|
||||
profiles = self._find_mapping_profiles(scvolume)
|
||||
for profile in profiles:
|
||||
# get our server
|
||||
scserver = None
|
||||
r = self.client.get('StorageCenter/ScServer/%s' %
|
||||
self._get_id(profile.get('server')))
|
||||
if self._check_result(r):
|
||||
scserver = self._get_json(r)
|
||||
# We do not want to whack our replication or live volume
|
||||
# connections. So anything other than a remote storage center
|
||||
# is fair game.
|
||||
if scserver and scserver['type'].upper() != 'REMOTESTORAGECENTER':
|
||||
# we can whack the connection.
|
||||
r = self.client.delete('StorageCenter/ScMappingProfile/%s'
|
||||
% self._get_id(profile),
|
||||
async_call=True)
|
||||
if self._check_result(r):
|
||||
# Check our result in the json.
|
||||
result = self._get_json(r)
|
||||
# EM 15.1 and 15.2 return a boolean directly.
|
||||
# 15.3 on up return it in a dict under 'result'.
|
||||
if result is True or (type(result) is dict and
|
||||
result.get('result')):
|
||||
LOG.info(
|
||||
'Volume %(vol)s unmapped from %(srv)s',
|
||||
{'vol': scvolume['name'],
|
||||
'srv': scserver['instanceName']})
|
||||
# yay, it is gone, carry on.
|
||||
continue
|
||||
|
||||
LOG.error('Unable to unmap %(vol)s from %(srv)s',
|
||||
{'vol': scvolume['name'],
|
||||
'srv': scserver['instanceName']})
|
||||
# 1 failed unmap is as good as 100.
|
||||
# Fail it and leave
|
||||
rtn = False
|
||||
break
|
||||
|
||||
return rtn
|
||||
|
||||
def get_storage_usage(self):
|
||||
"""Gets the storage usage object from the Dell backend.
|
||||
|
|
|
@ -75,14 +75,6 @@ class SCFCDriver(storagecenter_common.SCCommonDriver,
|
|||
self.configuration.safe_get('volume_backend_name') or 'Dell-FC'
|
||||
self.storage_protocol = 'FC'
|
||||
|
||||
def validate_connector(self, connector):
|
||||
"""Fail if connector doesn't contain all the data needed by driver.
|
||||
|
||||
Do a check on the connector and ensure that it has wwnns, wwpns.
|
||||
"""
|
||||
self.validate_connector_has_setting(connector, 'wwpns')
|
||||
self.validate_connector_has_setting(connector, 'wwnns')
|
||||
|
||||
@fczm_utils.add_fc_zone
|
||||
def initialize_connection(self, volume, connector):
|
||||
"""Initializes the connection and returns connection info.
|
||||
|
@ -203,8 +195,47 @@ class SCFCDriver(storagecenter_common.SCCommonDriver,
|
|||
'wwns': wwns})
|
||||
return None, [], {}
|
||||
|
||||
def force_detach(self, volume):
|
||||
"""Breaks all volume server connections including to the live volume.
|
||||
|
||||
:param volume: volume to be detached
|
||||
:raises VolumeBackendAPIException: On failure to sever connections.
|
||||
"""
|
||||
with self._client.open_connection() as api:
|
||||
volume_name = volume.get('id')
|
||||
provider_id = volume.get('provider_id')
|
||||
try:
|
||||
islivevol = self._is_live_vol(volume)
|
||||
scvolume = api.find_volume(volume_name, provider_id, islivevol)
|
||||
if scvolume:
|
||||
rtn = api.unmap_all(scvolume)
|
||||
# If this fails we blow up.
|
||||
if not rtn:
|
||||
raise exception.VolumeBackendAPIException(
|
||||
_('Terminate connection failed'))
|
||||
# If there is a livevol we just take a shot at
|
||||
# disconnecting.
|
||||
if islivevol:
|
||||
sclivevolume = api.get_live_volume(provider_id)
|
||||
if sclivevolume:
|
||||
self.terminate_secondary(api, sclivevolume, None)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error('Failed to terminates %(vol)s connections.',
|
||||
{'vol': volume_name})
|
||||
|
||||
# We don't know the servers that were involved so we just return
|
||||
# the most basic of data.
|
||||
info = {'driver_volume_type': 'fibre_channel',
|
||||
'data': {}}
|
||||
return info
|
||||
|
||||
@fczm_utils.remove_fc_zone
|
||||
def terminate_connection(self, volume, connector, force=False, **kwargs):
|
||||
# Special case
|
||||
if connector is None:
|
||||
return self.force_detach(volume)
|
||||
|
||||
# Grab some quick info.
|
||||
volume_name = volume.get('id')
|
||||
provider_id = volume.get('provider_id')
|
||||
|
|
|
@ -219,7 +219,40 @@ class SCISCSIDriver(storagecenter_common.SCCommonDriver,
|
|||
'init': initiatorname})
|
||||
return data
|
||||
|
||||
def force_detach(self, volume):
|
||||
"""Breaks all volume server connections including to the live volume.
|
||||
|
||||
:param volume: volume to be detached
|
||||
:raises VolumeBackendAPIException: On failure to sever connections.
|
||||
"""
|
||||
with self._client.open_connection() as api:
|
||||
volume_name = volume.get('id')
|
||||
provider_id = volume.get('provider_id')
|
||||
try:
|
||||
rtn = False
|
||||
islivevol = self._is_live_vol(volume)
|
||||
scvolume = api.find_volume(volume_name, provider_id, islivevol)
|
||||
if scvolume:
|
||||
rtn = api.unmap_all(scvolume)
|
||||
if rtn and islivevol:
|
||||
sclivevolume = api.get_live_volume(provider_id)
|
||||
if sclivevolume:
|
||||
rtn = self.terminate_secondary(api, sclivevolume,
|
||||
None)
|
||||
return rtn
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error('Failed to terminates %(vol)s connections.',
|
||||
{'vol': volume_name})
|
||||
raise exception.VolumeBackendAPIException(
|
||||
_('Terminate connection failed'))
|
||||
|
||||
def terminate_connection(self, volume, connector, force=False, **kwargs):
|
||||
# Special case
|
||||
if connector is None:
|
||||
return self.force_detach(volume)
|
||||
|
||||
# Normal terminate connection, then.
|
||||
# Grab some quick info.
|
||||
volume_name = volume.get('id')
|
||||
provider_id = volume.get('provider_id')
|
||||
|
@ -268,6 +301,8 @@ class SCISCSIDriver(storagecenter_common.SCCommonDriver,
|
|||
_('Terminate connection failed'))
|
||||
|
||||
def terminate_secondary(self, api, sclivevolume, initiatorname):
|
||||
# Only return False if we tried something and it failed.
|
||||
rtn = True
|
||||
secondaryvol = api.get_volume(
|
||||
sclivevolume['secondaryVolume']['instanceId'])
|
||||
if secondaryvol:
|
||||
|
@ -275,8 +310,9 @@ class SCISCSIDriver(storagecenter_common.SCCommonDriver,
|
|||
# Find our server.
|
||||
secondary = api.find_server(
|
||||
initiatorname, sclivevolume['secondaryScSerialNumber'])
|
||||
return api.unmap_volume(secondaryvol, secondary)
|
||||
rtn = api.unmap_volume(secondaryvol, secondary)
|
||||
else:
|
||||
return api.unmap_all(secondaryvol)
|
||||
rtn = api.unmap_all(secondaryvol)
|
||||
else:
|
||||
LOG.debug('terminate_secondary: secondary volume not found.')
|
||||
return rtn
|
||||
|
|
Loading…
Reference in New Issue