From d4b7d5fd427d3c46bb61a45edd2623305e23b90b Mon Sep 17 00:00:00 2001 From: Victor Rodionov Date: Wed, 16 Oct 2013 11:00:16 -0700 Subject: [PATCH] Nexenta drivers ignore "does not exist" exception Ignore "does not exist" exception in NFS and iSCSI driver, delete_volume and delete_snapshot methods. This exceptions means that the volume or the snapshot not exists in the backend, so we can avoid "delete" errors, when the resource was already deleted. Closes-Bug: 1240650 Change-Id: I3b2684097dcb95ba50a67c94a353dc3f17374777 --- cinder/tests/test_nexenta.py | 73 +++++++++++++++++++++++++- cinder/volume/drivers/nexenta/iscsi.py | 21 ++++---- cinder/volume/drivers/nexenta/nfs.py | 29 +++++++--- 3 files changed, 107 insertions(+), 16 deletions(-) diff --git a/cinder/tests/test_nexenta.py b/cinder/tests/test_nexenta.py index 437b9a789..b5318320c 100644 --- a/cinder/tests/test_nexenta.py +++ b/cinder/tests/test_nexenta.py @@ -24,6 +24,8 @@ import urllib2 import mox as mox_lib +from cinder import context +from cinder import db from cinder import test from cinder import units from cinder.volume import configuration as conf @@ -150,6 +152,14 @@ class TestNexentaISCSIDriver(test.TestCase): self.nms_mock.snapshot.destroy('cinder/volume1@snapshot1', '') self.mox.ReplayAll() self.drv.delete_snapshot(self.TEST_SNAPSHOT_REF) + self.mox.ResetAll() + + # Check that exception not raised if snapshot does not exist + mock = self.nms_mock.snapshot.destroy('cinder/volume1@snapshot1', '') + mock.AndRaise(nexenta.NexentaException( + 'Snapshot cinder/volume1@snapshot1 does not exist')) + self.mox.ReplayAll() + self.drv.delete_snapshot(self.TEST_SNAPSHOT_REF) _CREATE_EXPORT_METHODS = [ ('stmf', 'list_targets', tuple(), [], False, ), @@ -381,8 +391,18 @@ class TestNexentaNfsDriver(test.TestCase): 'root': 'nobody' } + def _create_volume_db_entry(self): + vol = { + 'id': '1', + 'size': 1, + 'status': 'available', + 'provider_location': self.TEST_EXPORT1 + } + return db.volume_create(self.ctxt, vol)['id'] + def setUp(self): super(TestNexentaNfsDriver, self).setUp() + self.ctxt = context.get_admin_context() self.configuration = mox_lib.MockObject(conf.Configuration) self.configuration.nexenta_shares_config = None self.configuration.nexenta_mount_point_base = '$state_path/mnt' @@ -392,7 +412,8 @@ class TestNexentaNfsDriver(test.TestCase): self.configuration.nfs_mount_options = None self.configuration.nexenta_nms_cache_volroot = False self.nms_mock = self.mox.CreateMockAnything() - for mod in ('appliance', 'folder', 'server', 'volume', 'netstorsvc'): + for mod in ('appliance', 'folder', 'server', 'volume', 'netstorsvc', + 'snapshot'): setattr(self.nms_mock, mod, self.mox.CreateMockAnything()) self.nms_mock.__hash__ = lambda *_, **__: 1 self.stubs.Set(jsonrpc, 'NexentaJSONProxy', @@ -594,3 +615,53 @@ class TestNexentaNfsDriver(test.TestCase): self.assertEqual(volume_name, 'stack') self.assertEqual(folder_name, 'share') + + def test_delete_snapshot(self): + self.drv.share2nms = {self.TEST_EXPORT1: self.nms_mock} + self._create_volume_db_entry() + + self.nms_mock.server.get_prop('volroot').AndReturn('/volumes') + self.nms_mock.snapshot.destroy('stack/share/volume-1@snapshot1', '') + self.mox.ReplayAll() + self.drv.delete_snapshot({'volume_id': '1', 'name': 'snapshot1'}) + self.mox.ResetAll() + + # Check that exception not raised if snapshot does not exist on + # NexentaStor appliance. + self.nms_mock.server.get_prop('volroot').AndReturn('/volumes') + mock = self.nms_mock.snapshot.destroy('stack/share/volume-1@snapshot1', + '') + mock.AndRaise(nexenta.NexentaException("Snapshot does not exist")) + self.mox.ReplayAll() + self.drv.delete_snapshot({'volume_id': '1', 'name': 'snapshot1'}) + self.mox.ResetAll() + + def test_delete_volume(self): + self.drv.share2nms = {self.TEST_EXPORT1: self.nms_mock} + self._create_volume_db_entry() + + self.drv._ensure_share_mounted = lambda *_, **__: 0 + self.drv._execute = lambda *_, **__: 0 + + self.nms_mock.server.get_prop('volroot').AndReturn('/volumes') + self.nms_mock.folder.destroy('stack/share/volume-1', '') + self.mox.ReplayAll() + self.drv.delete_volume({ + 'id': '1', + 'name': 'volume-1', + 'provider_location': self.TEST_EXPORT1 + }) + self.mox.ResetAll() + + # 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', '') + mock.AndRaise(nexenta.NexentaException("Folder does not exist")) + self.mox.ReplayAll() + self.drv.delete_volume({ + 'id': '1', + 'name': 'volume-1', + 'provider_location': self.TEST_EXPORT1 + }) + self.mox.ResetAll() diff --git a/cinder/volume/drivers/nexenta/iscsi.py b/cinder/volume/drivers/nexenta/iscsi.py index af4ec4ab1..87a942d6e 100644 --- a/cinder/volume/drivers/nexenta/iscsi.py +++ b/cinder/volume/drivers/nexenta/iscsi.py @@ -15,7 +15,7 @@ # License for the specific language governing permissions and limitations # under the License. """ -:mod:`nexenta.volume` -- Driver to store volumes on Nexenta Appliance +:mod:`nexenta.iscsi` -- Driver to store volumes on Nexenta Appliance ===================================================================== .. automodule:: nexenta.volume @@ -50,9 +50,10 @@ class NexentaISCSIDriver(driver.ISCSIDriver): # pylint: disable=R0921 1.0.1 - Fixed bug #1236626: catch "does not exist" exception of lu_exists. 1.1.0 - Changed class name to NexentaISCSIDriver. + 1.1.1 - Ignore "does not exist" exception of nms.snapshot.destroy. """ - VERSION = '1.1.0' + VERSION = '1.1.1' def __init__(self, *args, **kwargs): super(NexentaISCSIDriver, self).__init__(*args, **kwargs) @@ -137,7 +138,7 @@ class NexentaISCSIDriver(driver.ISCSIDriver): # pylint: disable=R0921 except nexenta.NexentaException as exc: if "does not exist" in exc.args[0]: LOG.info(_('Volume %s does not exist, it seems it was already ' - 'deleted'), volume['name']) + 'deleted.'), volume['name']) return if "zvol has children" in exc.args[0]: raise exception.VolumeIsBusy(volume_name=volume['name']) @@ -208,16 +209,18 @@ class NexentaISCSIDriver(driver.ISCSIDriver): # pylint: disable=R0921 :param snapshot: snapshot reference """ + volume_name = self._get_zvol_name(snapshot['volume_name']) + snapshot_name = '%s@%s' % (volume_name, snapshot['name']) try: - self.nms.snapshot.destroy( - '%s@%s' % (self._get_zvol_name(snapshot['volume_name']), - snapshot['name']), - '') + self.nms.snapshot.destroy(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 ' + 'already deleted.'), snapshot_name) + return if "snapshot has dependent clones" in exc.args[0]: raise exception.SnapshotIsBusy(snapshot_name=snapshot['name']) - else: - raise + raise def local_path(self, volume): """Return local path to existing local volume. diff --git a/cinder/volume/drivers/nexenta/nfs.py b/cinder/volume/drivers/nexenta/nfs.py index cbe89d679..d163d49db 100644 --- a/cinder/volume/drivers/nexenta/nfs.py +++ b/cinder/volume/drivers/nexenta/nfs.py @@ -15,8 +15,8 @@ # License for the specific language governing permissions and limitations # under the License. """ -:mod:`nexenta.nfs` -- Driver to store volumes on Nexenta Appliance -===================================================================== +:mod:`nexenta.nfs` -- Driver to store volumes on NexentaStor Appliance. +======================================================================= .. automodule:: nexenta.nfs .. moduleauthor:: Mikhail Khodos @@ -29,6 +29,7 @@ import os from oslo.config import cfg from cinder import context +from cinder import db from cinder import exception from cinder.openstack.common import log as logging from cinder import units @@ -38,7 +39,7 @@ from cinder.volume.drivers.nexenta import options from cinder.volume.drivers.nexenta import utils from cinder.volume.drivers import nfs -VERSION = '1.1.1' +VERSION = '1.1.2' LOG = logging.getLogger(__name__) CONF = cfg.CONF @@ -52,6 +53,8 @@ class NexentaNfsDriver(nfs.NfsDriver): # pylint: disable=R0921 1.0.0 - Initial driver version. 1.1.0 - Auto sharing for enclosing folder. 1.1.1 - Added caching for NexentaStor appliance 'volroot' value. + 1.1.2 - Ignore "folder does not exist" error in delete_volume and + delete_snapshot method. """ VERSION = VERSION @@ -217,7 +220,14 @@ class NexentaNfsDriver(nfs.NfsDriver): # pylint: disable=R0921 nms = self.share2nms[nfs_share] vol, parent_folder = self._get_share_datasets(nfs_share) folder = '%s/%s/%s' % (vol, parent_folder, volume['name']) - nms.folder.destroy(folder, '') + try: + nms.folder.destroy(folder, '') + except nexenta.NexentaException as exc: + if 'does not exist' in exc.args[0]: + LOG.info(_('Folder %s does not exist, it seems it was ' + 'already deleted.'), folder) + return + raise def create_snapshot(self, snapshot): """Creates a snapshot. @@ -241,7 +251,14 @@ class NexentaNfsDriver(nfs.NfsDriver): # pylint: disable=R0921 nms = self.share2nms[nfs_share] vol, dataset = self._get_share_datasets(nfs_share) folder = '%s/%s/%s' % (vol, dataset, volume['name']) - nms.snapshot.destroy('%s@%s' % (folder, snapshot['name']), '') + try: + 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 ' + 'already deleted.'), '%s@%s' % (folder, snapshot)) + return + raise def _create_sparsed_file(self, nms, path, size): """Creates file with 0 disk usage. @@ -387,7 +404,7 @@ class NexentaNfsDriver(nfs.NfsDriver): # pylint: disable=R0921 def _get_snapshot_volume(self, snapshot): ctxt = context.get_admin_context() - return self.db.volume_get(ctxt, snapshot['volume_id']) + return db.volume_get(ctxt, snapshot['volume_id']) def _get_volroot(self, nms): """Returns volroot property value from NexentaStor appliance.""" -- 2.45.2