Skip to content

Commit

Permalink
Nexenta: Remove snapshot after volume-clone deletion.
Browse files Browse the repository at this point in the history
Detect if volume was created via cloning and remove a snapshot from the
appliance if so. Return 'provider_location' to update the volume DB record
after creating a volume via cloning.

Closes-Bug: #1246079
Change-Id: I6c946d34871119600d7197614f5be22fa926e5dc
  • Loading branch information
keystone committed Nov 6, 2013
1 parent 54b117d commit e7319bc
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 8 deletions.
8 changes: 6 additions & 2 deletions cinder/tests/test_nexenta.py
Expand Up @@ -656,7 +656,9 @@ def test_delete_volume(self):
self.drv._execute = lambda *_, **__: 0

self.nms_mock.server.get_prop('volroot').AndReturn('/volumes')
self.nms_mock.folder.destroy('stack/share/volume-1', '')
self.nms_mock.folder.get_child_props('stack/share/volume-1',
'origin').AndReturn(None)
self.nms_mock.folder.destroy('stack/share/volume-1', '-r')
self.mox.ReplayAll()
self.drv.delete_volume({
'id': '1',
Expand All @@ -668,7 +670,9 @@ def test_delete_volume(self):
# Check that exception not raised if folder does not exist on
# NexentaStor appliance.
self.nms_mock.server.get_prop('volroot').AndReturn('/volumes')
mock = self.nms_mock.folder.destroy('stack/share/volume-1', '')
self.nms_mock.folder.get_child_props('stack/share/volume-1',
'origin').AndReturn(None)
mock = self.nms_mock.folder.destroy('stack/share/volume-1', '-r')
mock.AndRaise(nexenta.NexentaException("Folder does not exist"))
self.mox.ReplayAll()
self.drv.delete_volume({
Expand Down
34 changes: 28 additions & 6 deletions cinder/volume/drivers/nexenta/nfs.py
Expand Up @@ -191,13 +191,14 @@ def create_cloned_volume(self, volume, src_vref):
"""
LOG.info(_('Creating clone of volume: %s'), src_vref['id'])
snapshot = {'volume_name': src_vref['name'],
'name': 'cinder-clone-snap-%(id)s' % volume}
'volume_id': src_vref['id'],
'name': self._get_clone_snapshot_name(volume)}
# We don't delete this snapshot, because this snapshot will be origin
# of new volume. This snapshot will be automatically promoted by NMS
# when user will delete its origin.
self.create_snapshot(snapshot)
try:
self.create_volume_from_snapshot(volume, snapshot)
return self.create_volume_from_snapshot(volume, snapshot)
except nexenta.NexentaException:
LOG.error(_('Volume creation failed, deleting created snapshot '
'%(volume_name)s@%(name)s'), snapshot)
Expand All @@ -215,19 +216,31 @@ def delete_volume(self, volume):
"""
super(NexentaNfsDriver, self).delete_volume(volume)

nfs_share = volume['provider_location']
nfs_share = volume.get('provider_location')

if nfs_share:
nms = self.share2nms[nfs_share]
vol, parent_folder = self._get_share_datasets(nfs_share)
folder = '%s/%s/%s' % (vol, parent_folder, volume['name'])
props = nms.folder.get_child_props(folder, 'origin') or {}
try:
nms.folder.destroy(folder, '')
nms.folder.destroy(folder, '-r')
except nexenta.NexentaException as exc:
if 'does not exist' in exc.args[0]:
LOG.info(_('Folder %s does not exist, it seems it was '
LOG.info(_('Folder %s does not exist, it was '
'already deleted.'), folder)
return
raise
origin = props.get('origin')
if origin and self._is_clone_snapshot_name(origin):
try:
nms.snapshot.destroy(origin, '')
except nexenta.NexentaException as exc:
if 'does not exist' in exc.args[0]:
LOG.info(_('Snapshot %s does not exist, it was '
'already deleted.'), origin)
return
raise

def create_snapshot(self, snapshot):
"""Creates a snapshot.
Expand Down Expand Up @@ -255,7 +268,7 @@ def delete_snapshot(self, snapshot):
nms.snapshot.destroy('%s@%s' % (folder, snapshot['name']), '')
except nexenta.NexentaException as exc:
if 'does not exist' in exc.args[0]:
LOG.info(_('Snapshot %s does not exist, it seems it was '
LOG.info(_('Snapshot %s does not exist, it was '
'already deleted.'), '%s@%s' % (folder, snapshot))
return
raise
Expand Down Expand Up @@ -421,3 +434,12 @@ def _get_share_datasets(self, nfs_share):
volume_name = path.split('/')[0]
folder_name = '/'.join(path.split('/')[1:])
return volume_name, folder_name

def _get_clone_snapshot_name(self, volume):
"""Return name for snapshot that will be used to clone the volume."""
return 'cinder-clone-snapshot-%(id)s' % volume

def _is_clone_snapshot_name(self, snapshot):
"""Check if snapshot is created for cloning."""
name = snapshot.split('@')[-1]
return name.startswith('cinder-clone-snapshot-')

0 comments on commit e7319bc

Please sign in to comment.