Merge "ZFSSA handle non-existent snapshot" into stable/queens

This commit is contained in:
Zuul 2018-06-16 03:52:15 +00:00 committed by Gerrit Code Review
commit 3769a6915a
3 changed files with 47 additions and 39 deletions

View File

@ -441,7 +441,10 @@ class TestZFSSAISCSIDriver(test.TestCase):
}
}
cache = lun2del['origin']
self.drv.zfssa.num_clones.return_value = 0
self.drv.zfssa.get_lun_snapshot.return_value = {
'name': self.test_snap['name'],
'numclones': 0
}
self.drv._check_origin(lun2del, 'volname')
self.drv.zfssa.delete_lun.assert_called_once_with(
lcfg.zfssa_pool,
@ -449,7 +452,10 @@ class TestZFSSAISCSIDriver(test.TestCase):
cache['share'])
def test_create_delete_snapshot(self):
self.drv.zfssa.num_clones.return_value = 0
self.drv.zfssa.get_lun_snapshot.return_value = {
'name': self.test_snap['name'],
'numclones': 0
}
lcfg = self.configuration
self.drv.create_snapshot(self.test_snap)
self.drv.zfssa.create_snapshot.assert_called_once_with(
@ -464,6 +470,19 @@ class TestZFSSAISCSIDriver(test.TestCase):
self.test_snap['volume_name'],
self.test_snap['name'])
def test_delete_nonexistent_snapshot(self):
self.drv.zfssa.get_lun_snapshot.side_effect = \
exception.SnapshotNotFound(snapshot_id=self.test_snap['name'])
self.drv.delete_snapshot(self.test_snap)
self.drv.zfssa.delete_snapshot.assert_not_called()
def test_delete_snapshot_backend_fail(self):
self.drv.zfssa.get_lun_snapshot.side_effect = \
exception.VolumeBackendAPIException(data='fakemsg')
self.assertRaises(exception.VolumeBackendAPIException,
self.drv.delete_snapshot,
self.test_snap)
def test_create_volume_from_snapshot(self):
lcfg = self.configuration
self.drv.zfssa.get_lun.return_value = self.test_vol

View File

@ -375,11 +375,17 @@ class ZFSSAISCSIDriver(driver.ISCSIDriver):
"""Deletes a snapshot."""
LOG.debug('zfssa.delete_snapshot: snapshot=%s', snapshot['name'])
lcfg = self.configuration
numclones = self.zfssa.num_clones(lcfg.zfssa_pool,
lcfg.zfssa_project,
snapshot['volume_name'],
snapshot['name'])
if numclones > 0:
try:
snap2del = self.zfssa.get_lun_snapshot(lcfg.zfssa_pool,
lcfg.zfssa_project,
snapshot['volume_name'],
snapshot['name'])
except exception.SnapshotNotFound:
# If snapshot creation failed, it may exist in the database
# but not on the ZFSSA. Exit silently in this case.
return
if snap2del['numclones'] > 0:
LOG.error('Snapshot %s: has clones', snapshot['name'])
raise exception.SnapshotIsBusy(snapshot_name=snapshot['name'])
@ -1048,10 +1054,11 @@ class ZFSSAISCSIDriver(driver.ISCSIDriver):
if (cache['snapshot'].startswith('image-') and
cache['share'].startswith('os-cache-vol')):
try:
numclones = self.zfssa.num_clones(lcfg.zfssa_pool,
lcfg.zfssa_cache_project,
cache['share'],
cache['snapshot'])
snap = self.zfssa.get_lun_snapshot(lcfg.zfssa_pool,
lcfg.zfssa_cache_project,
cache['share'],
cache['snapshot'])
numclones = snap['numclones']
except Exception:
LOG.debug('Cache volume is already deleted.')
return

View File

@ -826,7 +826,15 @@ class ZFSSAApi(object):
project + '/luns/' + lun + '/snapshots/' + snapshot)
ret = self.rclient.get(svc)
if ret.status != restclient.Status.OK:
if ret.status == restclient.Status.NOT_FOUND:
LOG.warning('Snapshot %(snapshot)s of volume %(volume)s not '
'found in project %(project)s, pool %(pool)s.',
{'snapshot': snapshot,
'project': project,
'pool': pool,
'volume': lun})
raise exception.SnapshotNotFound(snapshot_id=snapshot)
elif ret.status != restclient.Status.OK:
exception_msg = ('Error Getting '
'Snapshot: %(snapshot)s of '
'Volume: %(lun)s in '
@ -841,7 +849,7 @@ class ZFSSAApi(object):
'ret.status': ret.status,
'ret.data': ret.data})
LOG.error(exception_msg)
raise exception.SnapshotNotFound(snapshot_id=snapshot)
raise exception.VolumeBackendAPIException(data=exception_msg)
val = json.loads(ret.data)['snapshot']
ret = {
@ -1022,32 +1030,6 @@ class ZFSSAApi(object):
LOG.error(exception_msg)
raise exception.VolumeBackendAPIException(data=exception_msg)
def num_clones(self, pool, project, lun, snapshot):
"""Checks whether snapshot has clones or not."""
svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
project + '/luns/' + lun + '/snapshots/' + snapshot
ret = self.rclient.get(svc)
if ret.status != restclient.Status.OK:
exception_msg = (_('Error Getting '
'Snapshot: %(snapshot)s on '
'Volume: %(lun)s to '
'Pool: %(pool)s '
'Project: %(project)s '
'Return code: %(ret.status)d '
'Message: %(ret.data)s.')
% {'snapshot': snapshot,
'lun': lun,
'pool': pool,
'project': project,
'ret.status': ret.status,
'ret.data': ret.data})
LOG.error(exception_msg)
raise exception.VolumeBackendAPIException(data=exception_msg)
val = json.loads(ret.data)
return val['snapshot']['numclones']
def get_initiator_initiatorgroup(self, initiator):
"""Returns the initiator group of the initiator."""
groups = []