From 6999c8d26bdef7f3a8795995e5605f8b85a7c584 Mon Sep 17 00:00:00 2001 From: Clinton Knight Date: Fri, 3 Apr 2015 11:08:58 -0400 Subject: [PATCH] NetApp cDOT driver is too strict in delete workflows If a share or share server is not created successfully, sometimes Manila will not save the vserver info in the share or share server object. In such cases, when asked to delete such a share or share server, the cDOT driver should not protest about the lack of vserver info but instead should log a warning and not raise an exception (which leaves the object in an error_deleting state). This patch addresses a number of issues in the delete, share-server-delete, and snapshot-delete workflows where the cDOT driver could unnecessarily raise an exception when it should merely do nothing and allow the workflow to proceed. Change-Id: I54cf96b8a24ac5272b37bce2f5118551504a1699 Closes-Bug: #1438893 --- manila/exception.py | 24 ++++- .../drivers/netapp/dataontap/client/api.py | 2 + .../netapp/dataontap/client/client_cmode.py | 38 ++++++- .../netapp/dataontap/cluster_mode/lib_base.py | 35 ++++++- .../dataontap/cluster_mode/lib_multi_svm.py | 28 ++++-- .../dataontap/cluster_mode/lib_single_svm.py | 4 +- .../drivers/netapp/dataontap/client/fakes.py | 56 +++++++++++ .../dataontap/client/test_client_cmode.py | 74 ++++++++++++-- .../dataontap/cluster_mode/test_lib_base.py | 99 +++++++++++++++++++ .../cluster_mode/test_lib_multi_svm.py | 36 +++++-- .../cluster_mode/test_lib_single_svm.py | 4 +- .../share/drivers/netapp/dataontap/fakes.py | 1 + 12 files changed, 369 insertions(+), 32 deletions(-) diff --git a/manila/exception.py b/manila/exception.py index 319637ac71..4836e92be0 100644 --- a/manila/exception.py +++ b/manila/exception.py @@ -498,12 +498,32 @@ class ServiceInstanceUnavailable(ServiceInstanceException): message = _("Service instance is not available.") +class StorageResourceException(ManilaException): + message = _("Storage resource exception.") + + +class StorageResourceNotFound(StorageResourceException): + message = _("Storage resource %(name)s not found.") + + +class SnapshotNotFound(StorageResourceNotFound): + message = _("Snapshot %(name)s not found.") + + +class SnapshotUnavailable(StorageResourceException): + message = _("Snapshot %(name)s info not available.") + + class NetAppException(ManilaException): message = _("Exception due to NetApp failure.") -class VserverUnavailable(NetAppException): - message = _("Vserver %(vserver)s is not available.") +class VserverNotFound(NetAppException): + message = _("Vserver %(vserver)s not found.") + + +class VserverNotSpecified(NetAppException): + message = _("Vserver not specified.") class EMCVnxXMLAPIError(Invalid): diff --git a/manila/share/drivers/netapp/dataontap/client/api.py b/manila/share/drivers/netapp/dataontap/client/api.py index 28ad080c09..c617aea0e5 100644 --- a/manila/share/drivers/netapp/dataontap/client/api.py +++ b/manila/share/drivers/netapp/dataontap/client/api.py @@ -33,10 +33,12 @@ LOG = log.getLogger(__name__) EONTAPI_EINVAL = '22' EAPINOTFOUND = '13005' +ESNAPSHOTNOTALLOWED = '13023' EVOLUMEOFFLINE = '13042' EINTERNALERROR = '13114' EDUPLICATEENTRY = '13130' EVOLNOTCLONE = '13170' +EVOL_NOT_MOUNTED = '14716' ESIS_CLONE_NOT_LICENSED = '14956' EOBJECTNOTFOUND = '15661' diff --git a/manila/share/drivers/netapp/dataontap/client/client_cmode.py b/manila/share/drivers/netapp/dataontap/client/client_cmode.py index f00fc98dd2..7af4e9f157 100644 --- a/manila/share/drivers/netapp/dataontap/client/client_cmode.py +++ b/manila/share/drivers/netapp/dataontap/client/client_cmode.py @@ -899,7 +899,12 @@ class NetAppCmodeClient(client_base.NetAppBaseClient): @na_utils.trace def offline_volume(self, volume_name): """Offlines a volume.""" - self.send_request('volume-offline', {'name': volume_name}) + try: + self.send_request('volume-offline', {'name': volume_name}) + except netapp_api.NaApiError as e: + if e.code == netapp_api.EVOLUMEOFFLINE: + return + raise @na_utils.trace def unmount_volume(self, volume_name, force=False): @@ -908,7 +913,12 @@ class NetAppCmodeClient(client_base.NetAppBaseClient): 'volume-name': volume_name, 'force': six.text_type(force).lower(), } - self.send_request('volume-unmount', api_args) + try: + self.send_request('volume-unmount', api_args) + except netapp_api.NaApiError as e: + if e.code == netapp_api.EVOL_NOT_MOUNTED: + return + raise @na_utils.trace def delete_volume(self, volume_name): @@ -944,11 +954,33 @@ class NetAppCmodeClient(client_base.NetAppBaseClient): } result = self.send_request('snapshot-get-iter', api_args) + error_record_list = result.get_child_by_name( + 'volume-errors') or netapp_api.NaElement('none') + errors = error_record_list.get_children() + + if errors: + error = errors[0] + error_code = error.get_child_content('errno') + error_reason = error.get_child_content('reason') + msg = _('Could not read information for snapshot %(name)s. ' + 'Code: %(code)s. Reason: %(reason)s') + msg_args = { + 'name': snapshot_name, + 'code': error_code, + 'reason': error_reason + } + if error_code == netapp_api.ESNAPSHOTNOTALLOWED: + raise exception.SnapshotUnavailable(msg % msg_args) + else: + raise exception.NetAppException(msg % msg_args) + attributes_list = result.get_child_by_name( 'attributes-list') or netapp_api.NaElement('none') snapshot_info_list = attributes_list.get_children() - if not self._has_records(result) or len(snapshot_info_list) != 1: + if not self._has_records(result): + raise exception.SnapshotNotFound(name=snapshot_name) + elif len(snapshot_info_list) > 1: msg = _('Could not find unique snapshot %(snap)s on ' 'volume %(vol)s.') msg_args = {'snap': snapshot_name, 'vol': volume_name} diff --git a/manila/share/drivers/netapp/dataontap/cluster_mode/lib_base.py b/manila/share/drivers/netapp/dataontap/cluster_mode/lib_base.py index b9d27322be..9dc09ede73 100644 --- a/manila/share/drivers/netapp/dataontap/cluster_mode/lib_base.py +++ b/manila/share/drivers/netapp/dataontap/cluster_mode/lib_base.py @@ -28,7 +28,7 @@ from oslo_utils import units import six from manila import exception -from manila.i18n import _, _LE, _LI +from manila.i18n import _, _LE, _LI, _LW from manila.openstack.common import loopingcall from manila.share.drivers.netapp.dataontap.client import client_cmode from manila.share.drivers.netapp.dataontap.protocols import cifs_cmode @@ -459,8 +459,19 @@ class NetAppCmodeFileStorageLibrary(object): @na_utils.trace def delete_share(self, context, share, share_server=None): """Deletes share.""" + try: + vserver, vserver_client = self._get_vserver( + share_server=share_server) + except (exception.InvalidInput, + exception.VserverNotSpecified, + exception.VserverNotFound) as error: + LOG.warning(_LW("Could not determine share server for share being " + "deleted: %(share)s. Deletion of share record " + "will proceed anyway. Error: %(error)s"), + {'share': share['id'], 'error': error}) + return + share_name = self._get_valid_share_name(share['id']) - vserver, vserver_client = self._get_vserver(share_server=share_server) if self._share_exists(share_name, vserver_client): self._remove_export(share, vserver_client) self._deallocate_container(share_name, vserver_client) @@ -516,11 +527,27 @@ class NetAppCmodeFileStorageLibrary(object): @na_utils.trace def delete_snapshot(self, context, snapshot, share_server=None): """Deletes a snapshot of a share.""" - vserver, vserver_client = self._get_vserver(share_server=share_server) + try: + vserver, vserver_client = self._get_vserver( + share_server=share_server) + except (exception.InvalidInput, + exception.VserverNotSpecified, + exception.VserverNotFound) as error: + LOG.warning(_LW("Could not determine share server for snapshot " + "being deleted: %(snap)s. Deletion of snapshot " + "record will proceed anyway. Error: %(error)s"), + {'snap': snapshot['id'], 'error': error}) + return + share_name = self._get_valid_share_name(snapshot['share_id']) snapshot_name = self._get_valid_snapshot_name(snapshot['id']) - self._handle_busy_snapshot(vserver_client, share_name, snapshot_name) + try: + self._handle_busy_snapshot(vserver_client, share_name, + snapshot_name) + except exception.SnapshotNotFound: + LOG.info(_LI("Snapshot %s does not exist."), snapshot_name) + return LOG.debug('Deleting snapshot %(snap)s for share %(share)s.', {'snap': snapshot_name, 'share': share_name}) diff --git a/manila/share/drivers/netapp/dataontap/cluster_mode/lib_multi_svm.py b/manila/share/drivers/netapp/dataontap/cluster_mode/lib_multi_svm.py index ca93b68559..fb7e99618a 100644 --- a/manila/share/drivers/netapp/dataontap/cluster_mode/lib_multi_svm.py +++ b/manila/share/drivers/netapp/dataontap/cluster_mode/lib_multi_svm.py @@ -80,7 +80,8 @@ class NetAppCmodeMultiSVMFileStorageLibrary( def _get_vserver(self, share_server=None): if not share_server: - raise exception.NetAppException(_('Share server not provided.')) + msg = _('Share server not provided') + raise exception.InvalidInput(reason=msg) backend_details = share_server.get('backend_details') vserver = backend_details.get( @@ -89,10 +90,10 @@ class NetAppCmodeMultiSVMFileStorageLibrary( if not vserver: msg = _('Vserver name is absent in backend details. Please ' 'check whether Vserver was created properly.') - raise exception.NetAppException(msg) + raise exception.VserverNotSpecified(msg) if not self._client.vserver_exists(vserver): - raise exception.VserverUnavailable(vserver=vserver) + raise exception.VserverNotFound(vserver=vserver) vserver_client = self._get_api_client(vserver) return vserver, vserver_client @@ -205,8 +206,23 @@ class NetAppCmodeMultiSVMFileStorageLibrary( @na_utils.trace def teardown_server(self, server_details, security_services=None): - """Teardown share network.""" - vserver = server_details['vserver_name'] + """Teardown share server.""" + vserver = server_details.get( + 'vserver_name') if server_details else None + + if not vserver: + LOG.warning(_LW("Vserver not specified for share server being " + "deleted. Deletion of share server record will " + "proceed anyway.")) + return + + elif not self._client.vserver_exists(vserver): + LOG.warning(_LW("Could not find Vserver for share server being " + "deleted: %s. Deletion of share server " + "record will proceed anyway."), vserver) + return + vserver_client = self._get_api_client(vserver=vserver) - self._client.delete_vserver(vserver, vserver_client, + self._client.delete_vserver(vserver, + vserver_client, security_services=security_services) diff --git a/manila/share/drivers/netapp/dataontap/cluster_mode/lib_single_svm.py b/manila/share/drivers/netapp/dataontap/cluster_mode/lib_single_svm.py index c38975be82..6346afe253 100644 --- a/manila/share/drivers/netapp/dataontap/cluster_mode/lib_single_svm.py +++ b/manila/share/drivers/netapp/dataontap/cluster_mode/lib_single_svm.py @@ -53,7 +53,7 @@ class NetAppCmodeSingleSVMFileStorageLibrary( # Ensure vserver exists. if not self._client.vserver_exists(self._vserver): - raise exception.VserverUnavailable(vserver=self._vserver) + raise exception.VserverNotFound(vserver=self._vserver) # If we have vserver credentials, ensure the vserver they connect # to matches the vserver specified in the configuration. @@ -95,7 +95,7 @@ class NetAppCmodeSingleSVMFileStorageLibrary( raise exception.InvalidInput(reason=msg) if not self._client.vserver_exists(self._vserver): - raise exception.VserverUnavailable(vserver=self._vserver) + raise exception.VserverNotFound(vserver=self._vserver) vserver_client = self._get_api_client(self._vserver) return self._vserver, vserver_client diff --git a/manila/tests/share/drivers/netapp/dataontap/client/fakes.py b/manila/tests/share/drivers/netapp/dataontap/client/fakes.py index 10208cd8ed..6b850d0c82 100644 --- a/manila/tests/share/drivers/netapp/dataontap/client/fakes.py +++ b/manila/tests/share/drivers/netapp/dataontap/client/fakes.py @@ -1019,6 +1019,62 @@ SNAPSHOT_GET_ITER_BUSY_RESPONSE = etree.XML(""" """ % {'snap': SNAPSHOT_NAME, 'volume': SHARE_NAME, 'vserver': VSERVER_NAME}) +SNAPSHOT_GET_ITER_NOT_UNIQUE_RESPONSE = etree.XML(""" + + + + false + %(snap)s + %(volume)s + %(vserver)s + + + false + %(snap)s + %(root_volume)s + %(admin_vserver)s + + + 1 + +""" % { + 'snap': SNAPSHOT_NAME, + 'volume': SHARE_NAME, + 'vserver': VSERVER_NAME, + 'root_volume': ROOT_VOLUME_NAME, + 'admin_vserver': ADMIN_VSERVER_NAME, +}) + +SNAPSHOT_GET_ITER_UNAVAILABLE_RESPONSE = etree.XML(""" + + 0 + + + 13023 + %(volume)s + Unable to get information for Snapshot copies of volume \ +"%(volume)s" on Vserver "%(vserver)s". Reason: Volume not online. + %(vserver)s + + + +""" % {'volume': SHARE_NAME, 'vserver': VSERVER_NAME}) + +SNAPSHOT_GET_ITER_OTHER_ERROR_RESPONSE = etree.XML(""" + + 0 + + + 99999 + %(volume)s + Unable to get information for Snapshot copies of volume \ +"%(volume)s" on Vserver "%(vserver)s". + %(vserver)s + + + +""" % {'volume': SHARE_NAME, 'vserver': VSERVER_NAME}) + NFS_EXPORT_RULES = ('10.10.10.10', '10.10.10.20') NFS_EXPORTFS_LIST_RULES_2_NO_RULES_RESPONSE = etree.XML(""" diff --git a/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py b/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py index 0b914d90a0..fa7d99e397 100644 --- a/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py +++ b/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py @@ -1594,6 +1594,30 @@ class NetAppClientCmodeTestCase(test.TestCase): self.client.send_request.assert_has_calls([ mock.call('volume-offline', volume_offline_args)]) + def test_offline_volume_already_offline(self): + + self.mock_object(self.client, + 'send_request', + mock.Mock(side_effect=self._mock_api_error( + netapp_api.EVOLUMEOFFLINE))) + + self.client.offline_volume(fake.SHARE_NAME) + + volume_offline_args = {'name': fake.SHARE_NAME} + + self.client.send_request.assert_has_calls([ + mock.call('volume-offline', volume_offline_args)]) + + def test_offline_volume_api_error(self): + + self.mock_object(self.client, + 'send_request', + mock.Mock(side_effect=self._mock_api_error())) + + self.assertRaises(netapp_api.NaApiError, + self.client.offline_volume, + fake.SHARE_NAME) + def test_unmount_volume(self): self.mock_object(self.client, 'send_request') @@ -1614,14 +1638,36 @@ class NetAppClientCmodeTestCase(test.TestCase): self.client.unmount_volume(fake.SHARE_NAME, force=True) - volume_unmount_args = { - 'volume-name': fake.SHARE_NAME, - 'force': 'true' - } + volume_unmount_args = {'volume-name': fake.SHARE_NAME, 'force': 'true'} self.client.send_request.assert_has_calls([ mock.call('volume-unmount', volume_unmount_args)]) + def test_unmount_volume_already_unmounted(self): + + self.mock_object(self.client, + 'send_request', + mock.Mock(side_effect=self._mock_api_error( + netapp_api.EVOL_NOT_MOUNTED))) + + self.client.unmount_volume(fake.SHARE_NAME, force=True) + + volume_unmount_args = {'volume-name': fake.SHARE_NAME, 'force': 'true'} + + self.client.send_request.assert_has_calls([ + mock.call('volume-unmount', volume_unmount_args)]) + + def test_unmount_volume_api_error(self): + + self.mock_object(self.client, + 'send_request', + mock.Mock(side_effect=self._mock_api_error())) + + self.assertRaises(netapp_api.NaApiError, + self.client.unmount_volume, + fake.SHARE_NAME, + force=True) + def test_delete_volume(self): self.mock_object(self.client, 'send_request') @@ -1696,14 +1742,28 @@ class NetAppClientCmodeTestCase(test.TestCase): mock.call('snapshot-get-iter', snapshot_get_iter_args)]) self.assertDictEqual(expected, result) - def test_get_snapshot_not_found(self): + @ddt.data({ + 'api_response_xml': fake.NO_RECORDS_RESPONSE, + 'raised_exception': exception.SnapshotNotFound, + }, { + 'api_response_xml': fake.SNAPSHOT_GET_ITER_NOT_UNIQUE_RESPONSE, + 'raised_exception': exception.NetAppException, + }, { + 'api_response_xml': fake.SNAPSHOT_GET_ITER_UNAVAILABLE_RESPONSE, + 'raised_exception': exception.SnapshotUnavailable, + }, { + 'api_response_xml': fake.SNAPSHOT_GET_ITER_OTHER_ERROR_RESPONSE, + 'raised_exception': exception.NetAppException, + }) + @ddt.unpack + def test_get_snapshot_error(self, api_response_xml, raised_exception): - api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE) + api_response = netapp_api.NaElement(api_response_xml) self.mock_object(self.client, 'send_request', mock.Mock(return_value=api_response)) - self.assertRaises(exception.NetAppException, + self.assertRaises(raised_exception, self.client.get_snapshot, fake.SHARE_NAME, fake.SNAPSHOT_NAME) diff --git a/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_base.py b/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_base.py index 5e266867d9..274671b19a 100644 --- a/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_base.py +++ b/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_base.py @@ -20,6 +20,7 @@ import copy import socket import time +import ddt import mock from oslo_log import log @@ -36,6 +37,7 @@ from manila import test from manila.tests.share.drivers.netapp.dataontap import fakes as fake +@ddt.ddt class NetAppFileStorageLibraryTestCase(test.TestCase): def setUp(self): @@ -49,6 +51,9 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): self.mock_object(lib_base.LOG, 'info', mock.Mock(side_effect=mock_logger.info)) + self.mock_object(lib_base.LOG, + 'warning', + mock.Mock(side_effect=mock_logger.warning)) self.mock_object(lib_base.LOG, 'error', mock.Mock(side_effect=mock_logger.error)) @@ -754,6 +759,30 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): vserver_client) self.assertEqual(0, lib_base.LOG.info.call_count) + @ddt.data(exception.InvalidInput(reason='fake_reason'), + exception.VserverNotSpecified(), + exception.VserverNotFound(vserver='fake_vserver')) + def test_delete_share_no_share_server(self, get_vserver_exception): + + self.mock_object(self.library, + '_get_vserver', + mock.Mock(side_effect=get_vserver_exception)) + mock_share_exists = self.mock_object(self.library, + '_share_exists', + mock.Mock(return_value=False)) + mock_remove_export = self.mock_object(self.library, '_remove_export') + mock_deallocate_container = self.mock_object(self.library, + '_deallocate_container') + + self.library.delete_share(self.context, + fake.SHARE, + share_server=fake.SHARE_SERVER) + + self.assertFalse(mock_share_exists.called) + self.assertFalse(mock_remove_export.called) + self.assertFalse(mock_deallocate_container.called) + self.assertEqual(1, lib_base.LOG.warning.call_count) + def test_delete_share_not_found(self): vserver_client = mock.Mock() @@ -891,6 +920,64 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): vserver_client.delete_snapshot.assert_called_once_with(share_name, snapshot_name) + @ddt.data(exception.InvalidInput(reason='fake_reason'), + exception.VserverNotSpecified(), + exception.VserverNotFound(vserver='fake_vserver')) + def test_delete_snapshot_no_share_server(self, get_vserver_exception): + + self.mock_object(self.library, + '_get_vserver', + mock.Mock(side_effect=get_vserver_exception)) + mock_handle_busy_snapshot = self.mock_object(self.library, + '_handle_busy_snapshot') + + self.library.delete_snapshot(self.context, + fake.SNAPSHOT, + share_server=fake.SHARE_SERVER) + + self.assertFalse(mock_handle_busy_snapshot.called) + self.assertEqual(1, lib_base.LOG.warning.call_count) + + def test_delete_snapshot_not_found(self): + + vserver_client = mock.Mock() + self.mock_object(self.library, + '_get_vserver', + mock.Mock(return_value=(fake.VSERVER1, + vserver_client))) + mock_handle_busy_snapshot = self.mock_object( + self.library, '_handle_busy_snapshot', + mock.Mock(side_effect=exception.SnapshotNotFound( + name=fake.SNAPSHOT_NAME))) + + self.library.delete_snapshot(self.context, + fake.SNAPSHOT, + share_server=fake.SHARE_SERVER) + + self.assertTrue(mock_handle_busy_snapshot.called) + self.assertFalse(vserver_client.delete_snapshot.called) + + def test_delete_snapshot_busy(self): + + vserver_client = mock.Mock() + self.mock_object(self.library, + '_get_vserver', + mock.Mock(return_value=(fake.VSERVER1, + vserver_client))) + mock_handle_busy_snapshot = self.mock_object( + self.library, '_handle_busy_snapshot', + mock.Mock(side_effect=exception.ShareSnapshotIsBusy( + snapshot_name=fake.SNAPSHOT_NAME))) + + self.assertRaises(exception.ShareSnapshotIsBusy, + self.library.delete_snapshot, + self.context, + fake.SNAPSHOT, + share_server=fake.SHARE_SERVER) + + self.assertTrue(mock_handle_busy_snapshot.called) + self.assertFalse(vserver_client.delete_snapshot.called) + def test_handle_busy_snapshot_not_busy(self): vserver_client = mock.Mock() @@ -904,6 +991,18 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): self.assertEqual(1, vserver_client.get_snapshot.call_count) self.assertEqual(0, lib_base.LOG.debug.call_count) + def test_handle_busy_snapshot_not_found(self): + + vserver_client = mock.Mock() + vserver_client.get_snapshot.side_effect = exception.SnapshotNotFound( + name=fake.SNAPSHOT_NAME) + + self.assertRaises(exception.SnapshotNotFound, + self.library._handle_busy_snapshot, + vserver_client, + fake.SHARE_NAME, + fake.SNAPSHOT_NAME) + def test_handle_busy_snapshot_not_clone_dependency(self): snapshot = copy.deepcopy(fake.CDOT_SNAPSHOT_BUSY_VOLUME_CLONE) diff --git a/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_multi_svm.py b/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_multi_svm.py index 0e6ace13a2..304ebb5e6f 100644 --- a/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_multi_svm.py +++ b/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_multi_svm.py @@ -121,7 +121,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): def test_get_vserver_no_share_server(self): - self.assertRaises(exception.NetAppException, + self.assertRaises(exception.InvalidInput, self.library._get_vserver) def test_get_vserver_no_backend_details(self): @@ -130,7 +130,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): fake_share_server.pop('backend_details') kwargs = {'share_server': fake_share_server} - self.assertRaises(exception.NetAppException, + self.assertRaises(exception.VserverNotSpecified, self.library._get_vserver, **kwargs) @@ -140,7 +140,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): fake_share_server['backend_details'] = None kwargs = {'share_server': fake_share_server} - self.assertRaises(exception.NetAppException, + self.assertRaises(exception.VserverNotSpecified, self.library._get_vserver, **kwargs) @@ -150,7 +150,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): fake_share_server['backend_details'].pop('vserver_name') kwargs = {'share_server': fake_share_server} - self.assertRaises(exception.NetAppException, + self.assertRaises(exception.VserverNotSpecified, self.library._get_vserver, **kwargs) @@ -160,7 +160,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): fake_share_server['backend_details']['vserver_name'] = None kwargs = {'share_server': fake_share_server} - self.assertRaises(exception.NetAppException, + self.assertRaises(exception.VserverNotSpecified, self.library._get_vserver, **kwargs) @@ -169,7 +169,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): self.library._client.vserver_exists.return_value = False kwargs = {'share_server': fake.SHARE_SERVER} - self.assertRaises(exception.VserverUnavailable, + self.assertRaises(exception.VserverNotFound, self.library._get_vserver, **kwargs) @@ -432,12 +432,36 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): self.mock_object(self.library, '_get_api_client', mock.Mock(return_value=vserver_client)) + self.library._client.vserver_exists.return_value = True self.library.teardown_server( fake.SHARE_SERVER['backend_details'], security_services=fake.NETWORK_INFO['security_services']) + self.library._client.vserver_exists.assert_called_once_with( + fake.VSERVER1) self.library._client.delete_vserver.assert_called_once_with( fake.VSERVER1, vserver_client, security_services=fake.NETWORK_INFO['security_services']) + + @ddt.data(None, {}, {'vserver_name': None}) + def test_teardown_server_no_share_server(self, server_details): + + self.library.teardown_server(server_details) + + self.assertFalse(self.library._client.delete_vserver.called) + self.assertTrue(lib_multi_svm.LOG.warning.called) + + def test_teardown_server_no_vserver(self): + + self.library._client.vserver_exists.return_value = False + + self.library.teardown_server( + fake.SHARE_SERVER['backend_details'], + security_services=fake.NETWORK_INFO['security_services']) + + self.library._client.vserver_exists.assert_called_once_with( + fake.VSERVER1) + self.assertFalse(self.library._client.delete_vserver.called) + self.assertTrue(lib_multi_svm.LOG.warning.called) diff --git a/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_single_svm.py b/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_single_svm.py index f222c3147c..fa152308dd 100644 --- a/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_single_svm.py +++ b/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_single_svm.py @@ -83,7 +83,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): def test_check_for_setup_error_vserver_not_found(self): self.library._client.vserver_exists.return_value = False - self.assertRaises(exception.VserverUnavailable, + self.assertRaises(exception.VserverNotFound, self.library.check_for_setup_error) def test_check_for_setup_error_cluster_creds_vserver_match(self): @@ -145,7 +145,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): def test_get_vserver_vserver_not_found(self): self.library._client.vserver_exists.return_value = False - self.assertRaises(exception.VserverUnavailable, + self.assertRaises(exception.VserverNotFound, self.library._get_vserver) def test_find_matching_aggregates(self): diff --git a/manila/tests/share/drivers/netapp/dataontap/fakes.py b/manila/tests/share/drivers/netapp/dataontap/fakes.py index ef166f3ca1..a80a776943 100644 --- a/manila/tests/share/drivers/netapp/dataontap/fakes.py +++ b/manila/tests/share/drivers/netapp/dataontap/fakes.py @@ -179,6 +179,7 @@ NETWORK_INFO = { NETWORK_INFO_NETMASK = '255.255.255.0' SHARE_SERVER = { + 'share_network_id': 'c5b3a865-56d0-4d88-abe5-879965e099c9', 'backend_details': { 'vserver_name': VSERVER1 }