[NetApp] Fix svm scoped account

When the NetApp backend starts, it needs to know whether the
`revert_to_snapshot` support exist. So, it was retrieving the
licenses and checking if the `SnapRestore` is included. Using a
scoped account, the backend cannot retrieve that information,
though. So, this patch solves it by sending a fake operation
`revert_to_snapshot` that must fail. Analyzing the given error, it
sets the backend support field.

Closes-Bug: #1882590
Change-Id: Ib71a6cec939288498e48736f129fbfdacaabe9da
(cherry picked from commit 6f58af1ae3)
(cherry picked from commit b5e541a628)
(cherry picked from commit b252cb801d)
(cherry picked from commit 036908dd59)
(cherry picked from commit a9bc395407)
This commit is contained in:
Felipe Rodrigues 2020-06-05 15:28:01 +00:00 committed by Douglas Viroel
parent 0d5a1873f2
commit bbf4d72556
4 changed files with 86 additions and 26 deletions

View File

@ -30,6 +30,7 @@ from oslo_log import log
from oslo_service import loopingcall
from oslo_utils import timeutils
from oslo_utils import units
from oslo_utils import uuidutils
import six
from manila.common import constants
@ -116,6 +117,7 @@ class NetAppCmodeFileStorageLibrary(object):
self._clients = {}
self._ssc_stats = {}
self._have_cluster_creds = None
self._revert_to_snapshot_support = False
self._cluster_info = {}
self._app_version = kwargs.get('app_version', 'unknown')
@ -132,6 +134,9 @@ class NetAppCmodeFileStorageLibrary(object):
if self._have_cluster_creds is True:
self._set_cluster_info()
self._licenses = self._get_licenses()
self._revert_to_snapshot_support = self._check_snaprestore_license()
# Performance monitoring library
self._perf_library = performance.PerformanceLibrary(self._client)
@ -143,7 +148,6 @@ class NetAppCmodeFileStorageLibrary(object):
@na_utils.trace
def check_for_setup_error(self):
self._licenses = self._get_licenses()
self._start_periodic_tasks()
def _get_vserver(self, share_server=None):
@ -247,10 +251,30 @@ class NetAppCmodeFileStorageLibrary(object):
@na_utils.trace
def _check_snaprestore_license(self):
"""Check if snaprestore license is enabled."""
if not self._licenses:
self._licenses = self._client.get_licenses()
if self._have_cluster_creds:
return 'snaprestore' in self._licenses
else:
# NOTE: (felipe_rodrigues): workaround to find out whether the
# backend has the license: since without cluster credentials it
# cannot retrieve the ontap licenses, it sends a fake ONTAP
# "snapshot-restore-volume" request which is only available when
# the license exists. By the got error, it checks whether license
# is installed or not.
try:
self._client.restore_snapshot(
"fake_%s" % uuidutils.generate_uuid(dashed=False), "")
except netapp_api.NaApiError as e:
no_license = 'is not licensed'
LOG.debug('Fake restore_snapshot request failed: %s', e)
return not (e.code == netapp_api.EAPIERROR and
no_license in e.message)
return 'snaprestore' in self._licenses
# since it passed an empty snapshot, it should never get here
msg = _("Caught an unexpected behavior: the fake restore to "
"snapshot request using 'fake' volume and empty string "
"snapshot as argument has not failed.")
LOG.exception(msg)
raise exception.NetAppException(msg)
@na_utils.trace
def _get_aggregate_node(self, aggregate_name):
@ -323,8 +347,6 @@ class NetAppCmodeFileStorageLibrary(object):
netapp_flexvol_encryption = self._cluster_info.get(
'nve_support', False)
revert_to_snapshot_support = self._check_snaprestore_license()
for aggr_name in sorted(aggregates):
reserved_percentage = self.configuration.reserved_share_percentage
@ -354,7 +376,7 @@ class NetAppCmodeFileStorageLibrary(object):
'thin_provisioning': [True, False],
'snapshot_support': True,
'create_share_from_snapshot_support': True,
'revert_to_snapshot_support': revert_to_snapshot_support,
'revert_to_snapshot_support': self._revert_to_snapshot_support,
}
# Add storage service catalog data.

View File

@ -118,8 +118,16 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
self.mock_object(
self.library._client, 'check_for_cluster_credentials',
mock.Mock(return_value=True))
self.mock_object(
self.library, '_check_snaprestore_license',
mock.Mock(return_value=True))
self.mock_object(
self.library,
'_get_licenses',
mock.Mock(return_value=fake.LICENSES))
self.library.do_setup(self.context)
self.assertEqual(fake.LICENSES, self.library._licenses)
mock_get_api_client.assert_called_once_with()
(self.library._client.check_for_cluster_credentials.
assert_called_once_with())
@ -127,6 +135,9 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
self.mock_object(self.library._client,
'check_for_cluster_credentials',
mock.Mock(return_value=True))
self.mock_object(
self.library, '_check_snaprestore_license',
mock.Mock(return_value=True))
mock_set_cluster_info = self.mock_object(
self.library, '_set_cluster_info')
self.library.do_setup(self.context)
@ -138,17 +149,10 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
fake.CLUSTER_NODES)
def test_check_for_setup_error(self):
self.library._licenses = []
self.mock_object(self.library,
'_get_licenses',
mock.Mock(return_value=['fake_license']))
mock_start_periodic_tasks = self.mock_object(self.library,
'_start_periodic_tasks')
self.library.check_for_setup_error()
self.assertEqual(['fake_license'], self.library._licenses)
mock_start_periodic_tasks.assert_called_once_with()
def test_get_vserver(self):
@ -333,7 +337,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
assert_called_once_with(fake.AGGREGATES))
self.assertDictEqual(fake.AGGREGATE_CAPACITIES, result)
def test_check_snaprestore_license_notfound(self):
def test_check_snaprestore_license_admin_notfound(self):
self.library._have_cluster_creds = True
licenses = list(fake.LICENSES)
licenses.remove('snaprestore')
self.mock_object(self.client,
@ -342,13 +347,44 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
result = self.library._check_snaprestore_license()
self.assertIs(False, result)
def test_check_snaprestore_license_found(self):
self.mock_object(self.client,
'get_licenses',
mock.Mock(return_value=fake.LICENSES))
def test_check_snaprestore_license_admin_found(self):
self.library._have_cluster_creds = True
self.library._licenses = fake.LICENSES
result = self.library._check_snaprestore_license()
self.assertIs(True, result)
def test_check_snaprestore_license_svm_scoped_notfound(self):
self.library._have_cluster_creds = False
self.mock_object(self.library._client,
'restore_snapshot',
mock.Mock(side_effect=netapp_api.NaApiError(
code=netapp_api.EAPIERROR,
message=fake.NO_SNAPRESTORE_LICENSE)))
result = self.library._check_snaprestore_license()
self.assertIs(False, result)
def test_check_snaprestore_license_svm_scoped_found(self):
self.library._have_cluster_creds = False
self.mock_object(self.library._client,
'restore_snapshot',
mock.Mock(side_effect=netapp_api.NaApiError(
code=netapp_api.EAPIERROR,
message='Other error')))
result = self.library._check_snaprestore_license()
self.assertIs(True, result)
def test_check_snaprestore_license_svm_scoped_found_exception(self):
self.mock_object(lib_base.LOG, 'exception')
self.library._have_cluster_creds = False
self.mock_object(self.library._client,
'restore_snapshot',
mock.Mock(return_value=None))
self.assertRaises(
exception.NetAppException,
self.library._check_snaprestore_license)
lib_base.LOG.exception.assert_called_once()
def test_get_aggregate_node_cluster_creds(self):
self.library._have_cluster_creds = True
@ -449,13 +485,11 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
self.library, '_get_aggregate_space',
mock.Mock(return_value=fake.AGGREGATE_CAPACITIES))
self.library._have_cluster_creds = True
self.library._revert_to_snapshot_support = True
self.library._cluster_info = fake.CLUSTER_INFO
self.library._ssc_stats = fake.SSC_INFO
self.library._perf_library.get_node_utilization_for_pool = (
mock.Mock(side_effect=[30.0, 42.0]))
self.mock_object(self.library,
'_check_snaprestore_license',
mock.Mock(return_value=True))
result = self.library._get_pools(filter_function='filter',
goodness_function='goodness')
@ -468,13 +502,11 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
self.library, '_get_aggregate_space',
mock.Mock(return_value=fake.AGGREGATE_CAPACITIES_VSERVER_CREDS))
self.library._have_cluster_creds = False
self.library._revert_to_snapshot_support = True
self.library._cluster_info = fake.CLUSTER_INFO
self.library._ssc_stats = fake.SSC_INFO_VSERVER_CREDS
self.library._perf_library.get_node_utilization_for_pool = (
mock.Mock(side_effect=[50.0, 50.0]))
self.mock_object(self.library,
'_check_snaprestore_license',
mock.Mock(return_value=True))
result = self.library._get_pools()

View File

@ -18,7 +18,7 @@ import copy
from manila.common import constants
import manila.tests.share.drivers.netapp.fakes as na_fakes
NO_SNAPRESTORE_LICENSE = '"SnapRestore" is not licensed in the cluster.'
BACKEND_NAME = 'fake_backend_name'
DRIVER_NAME = 'fake_driver_name'
APP_VERSION = 'fake_app_vsersion'

View File

@ -0,0 +1,6 @@
---
fixes:
- |
Fixed `bug #1882590 <https://bugs.launchpad.net/manila/+bug/1882590>`_
that caused an error on starting a NetApp backend when using the SVM
scoped account.