ZFSSA iSCSI delete volume with non-existent LUN
Under some circumstances, a volume can exist in cinder for which there is no corresponding LUN on the ZFSSA. This fix allows deletion of the volume in such cases, by catching the NOT_FOUND status from the ZFSSA REST API and translating it to a VolumeNotFound exception, and then considering that exception to be non-fatal, whilst passing up any other exception that may be encountered. This way, some other failure in using the REST API to obtain LUN information (e.g. transient network failure) will not cause the cinder volume to get blindly deleted, which would have left behind an orphaned LUN on the ZFSSA. Change-Id: I332163fa35a2aa3f6f921b805fa97c803ec10724 Closes-Bug: #1537914
This commit is contained in:
parent
583b902511
commit
e68b879ef0
|
@ -390,6 +390,19 @@ class TestZFSSAISCSIDriver(test.TestCase):
|
|||
project=lcfg.zfssa_project,
|
||||
lun=self.test_vol['name'])
|
||||
|
||||
def test_delete_volume_with_missing_lun(self):
|
||||
self.drv.zfssa.get_lun.side_effect = exception.VolumeNotFound(
|
||||
volume_id=self.test_vol['name'])
|
||||
self.drv.delete_volume(self.test_vol)
|
||||
self.drv.zfssa.delete_lun.assert_not_called()
|
||||
|
||||
def test_delete_volume_backend_fail(self):
|
||||
self.drv.zfssa.get_lun.side_effect = \
|
||||
exception.VolumeBackendAPIException(data='fakemsg')
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.drv.delete_volume,
|
||||
self.test_vol)
|
||||
|
||||
@mock.patch.object(iscsi.ZFSSAISCSIDriver, '_check_origin')
|
||||
def test_delete_cache_volume(self, _check_origin):
|
||||
lcfg = self.configuration
|
||||
|
|
|
@ -327,24 +327,23 @@ class ZFSSAISCSIDriver(driver.ISCSIDriver):
|
|||
lcfg.zfssa_target_group,
|
||||
specs)
|
||||
|
||||
@utils.trace
|
||||
def delete_volume(self, volume):
|
||||
"""Deletes a volume with the given volume['name']."""
|
||||
LOG.debug('zfssa.delete_volume: name=%s', volume['name'])
|
||||
lcfg = self.configuration
|
||||
|
||||
try:
|
||||
lun2del = self.zfssa.get_lun(lcfg.zfssa_pool,
|
||||
lcfg.zfssa_project,
|
||||
volume['name'])
|
||||
except exception.VolumeBackendAPIException as ex:
|
||||
# NOTE(jdg): This will log an error and continue
|
||||
# if for some reason the volume no longer exists
|
||||
# on the backend
|
||||
if 'Error Getting Volume' in ex.message:
|
||||
LOG.error("Volume ID %s was not found on "
|
||||
"the zfssa device while attempting "
|
||||
"delete_volume operation.", volume['id'])
|
||||
return
|
||||
except exception.VolumeNotFound:
|
||||
# Sometimes a volume exists in cinder for which there is no
|
||||
# corresponding LUN (e.g. LUN create failed). In this case,
|
||||
# allow deletion to complete (without doing anything on the
|
||||
# ZFSSA). Any other exception should be passed up.
|
||||
LOG.warning('No LUN found on ZFSSA corresponding to volume '
|
||||
'ID %s.', volume['id'])
|
||||
return
|
||||
|
||||
# Delete clone temp snapshot. see create_cloned_volume()
|
||||
if 'origin' in lun2del and 'id' in volume:
|
||||
|
|
|
@ -730,7 +730,18 @@ class ZFSSAApi(object):
|
|||
svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
|
||||
project + "/luns/" + lun
|
||||
ret = self.rclient.get(svc)
|
||||
if ret.status != restclient.Status.OK:
|
||||
if ret.status == restclient.Status.NOT_FOUND:
|
||||
# Sometimes a volume exists in cinder for which there is no
|
||||
# corresponding LUN (e.g. LUN create failed). In this case,
|
||||
# allow deletion to complete (without doing anything on the
|
||||
# ZFSSA). Any other exception should be passed up.
|
||||
LOG.warning('LUN with name %(lun)s not found in project '
|
||||
'%(project)s, pool %(pool)s.',
|
||||
{'lun': lun,
|
||||
'project': project,
|
||||
'pool': pool})
|
||||
raise exception.VolumeNotFound(volume_id=lun)
|
||||
elif ret.status != restclient.Status.OK:
|
||||
exception_msg = (_('Error Getting '
|
||||
'Volume: %(lun)s on '
|
||||
'Pool: %(pool)s '
|
||||
|
@ -743,7 +754,7 @@ class ZFSSAApi(object):
|
|||
'ret.status': ret.status,
|
||||
'ret.data': ret.data})
|
||||
LOG.error(exception_msg)
|
||||
raise exception.VolumeNotFound(volume_id=lun)
|
||||
raise exception.VolumeBackendAPIException(data=exception_msg)
|
||||
|
||||
val = json.loads(ret.data)
|
||||
ret = {
|
||||
|
|
Loading…
Reference in New Issue