[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
This commit is contained in:
parent
bbea70d044
commit
6f58af1ae3
@ -30,6 +30,7 @@ from oslo_log import log
|
|||||||
from oslo_service import loopingcall
|
from oslo_service import loopingcall
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
from oslo_utils import units
|
from oslo_utils import units
|
||||||
|
from oslo_utils import uuidutils
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from manila.common import constants
|
from manila.common import constants
|
||||||
@ -129,6 +130,7 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||||||
self._clients = {}
|
self._clients = {}
|
||||||
self._ssc_stats = {}
|
self._ssc_stats = {}
|
||||||
self._have_cluster_creds = None
|
self._have_cluster_creds = None
|
||||||
|
self._revert_to_snapshot_support = False
|
||||||
self._cluster_info = {}
|
self._cluster_info = {}
|
||||||
|
|
||||||
self._app_version = kwargs.get('app_version', 'unknown')
|
self._app_version = kwargs.get('app_version', 'unknown')
|
||||||
@ -145,6 +147,9 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||||||
if self._have_cluster_creds is True:
|
if self._have_cluster_creds is True:
|
||||||
self._set_cluster_info()
|
self._set_cluster_info()
|
||||||
|
|
||||||
|
self._licenses = self._get_licenses()
|
||||||
|
self._revert_to_snapshot_support = self._check_snaprestore_license()
|
||||||
|
|
||||||
# Performance monitoring library
|
# Performance monitoring library
|
||||||
self._perf_library = performance.PerformanceLibrary(self._client)
|
self._perf_library = performance.PerformanceLibrary(self._client)
|
||||||
|
|
||||||
@ -156,7 +161,6 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||||||
|
|
||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
def check_for_setup_error(self):
|
def check_for_setup_error(self):
|
||||||
self._licenses = self._get_licenses()
|
|
||||||
self._start_periodic_tasks()
|
self._start_periodic_tasks()
|
||||||
|
|
||||||
def _get_vserver(self, share_server=None):
|
def _get_vserver(self, share_server=None):
|
||||||
@ -260,10 +264,30 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
def _check_snaprestore_license(self):
|
def _check_snaprestore_license(self):
|
||||||
"""Check if snaprestore license is enabled."""
|
"""Check if snaprestore license is enabled."""
|
||||||
if not self._licenses:
|
if self._have_cluster_creds:
|
||||||
self._licenses = self._client.get_licenses()
|
|
||||||
|
|
||||||
return 'snaprestore' in self._licenses
|
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)
|
||||||
|
|
||||||
|
# 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
|
@na_utils.trace
|
||||||
def _get_aggregate_node(self, aggregate_name):
|
def _get_aggregate_node(self, aggregate_name):
|
||||||
@ -335,8 +359,6 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||||||
netapp_flexvol_encryption = self._cluster_info.get(
|
netapp_flexvol_encryption = self._cluster_info.get(
|
||||||
'nve_support', False)
|
'nve_support', False)
|
||||||
|
|
||||||
revert_to_snapshot_support = self._check_snaprestore_license()
|
|
||||||
|
|
||||||
for aggr_name in sorted(aggregates):
|
for aggr_name in sorted(aggregates):
|
||||||
|
|
||||||
reserved_percentage = self.configuration.reserved_share_percentage
|
reserved_percentage = self.configuration.reserved_share_percentage
|
||||||
@ -368,7 +390,7 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||||||
'thin_provisioning': [True, False],
|
'thin_provisioning': [True, False],
|
||||||
'snapshot_support': True,
|
'snapshot_support': True,
|
||||||
'create_share_from_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.
|
# Add storage service catalog data.
|
||||||
|
@ -118,8 +118,16 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
self.mock_object(
|
self.mock_object(
|
||||||
self.library._client, 'check_for_cluster_credentials',
|
self.library._client, 'check_for_cluster_credentials',
|
||||||
mock.Mock(return_value=True))
|
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.library.do_setup(self.context)
|
||||||
|
|
||||||
|
self.assertEqual(fake.LICENSES, self.library._licenses)
|
||||||
mock_get_api_client.assert_called_once_with()
|
mock_get_api_client.assert_called_once_with()
|
||||||
(self.library._client.check_for_cluster_credentials.
|
(self.library._client.check_for_cluster_credentials.
|
||||||
assert_called_once_with())
|
assert_called_once_with())
|
||||||
@ -127,6 +135,9 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
self.mock_object(self.library._client,
|
self.mock_object(self.library._client,
|
||||||
'check_for_cluster_credentials',
|
'check_for_cluster_credentials',
|
||||||
mock.Mock(return_value=True))
|
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(
|
mock_set_cluster_info = self.mock_object(
|
||||||
self.library, '_set_cluster_info')
|
self.library, '_set_cluster_info')
|
||||||
self.library.do_setup(self.context)
|
self.library.do_setup(self.context)
|
||||||
@ -138,17 +149,10 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
fake.CLUSTER_NODES)
|
fake.CLUSTER_NODES)
|
||||||
|
|
||||||
def test_check_for_setup_error(self):
|
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,
|
mock_start_periodic_tasks = self.mock_object(self.library,
|
||||||
'_start_periodic_tasks')
|
'_start_periodic_tasks')
|
||||||
|
|
||||||
self.library.check_for_setup_error()
|
self.library.check_for_setup_error()
|
||||||
|
|
||||||
self.assertEqual(['fake_license'], self.library._licenses)
|
|
||||||
mock_start_periodic_tasks.assert_called_once_with()
|
mock_start_periodic_tasks.assert_called_once_with()
|
||||||
|
|
||||||
def test_get_vserver(self):
|
def test_get_vserver(self):
|
||||||
@ -333,7 +337,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
assert_called_once_with(fake.AGGREGATES))
|
assert_called_once_with(fake.AGGREGATES))
|
||||||
self.assertDictEqual(fake.AGGREGATE_CAPACITIES, result)
|
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 = list(fake.LICENSES)
|
||||||
licenses.remove('snaprestore')
|
licenses.remove('snaprestore')
|
||||||
self.mock_object(self.client,
|
self.mock_object(self.client,
|
||||||
@ -342,13 +347,44 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
result = self.library._check_snaprestore_license()
|
result = self.library._check_snaprestore_license()
|
||||||
self.assertIs(False, result)
|
self.assertIs(False, result)
|
||||||
|
|
||||||
def test_check_snaprestore_license_found(self):
|
def test_check_snaprestore_license_admin_found(self):
|
||||||
self.mock_object(self.client,
|
self.library._have_cluster_creds = True
|
||||||
'get_licenses',
|
self.library._licenses = fake.LICENSES
|
||||||
mock.Mock(return_value=fake.LICENSES))
|
|
||||||
result = self.library._check_snaprestore_license()
|
result = self.library._check_snaprestore_license()
|
||||||
self.assertIs(True, result)
|
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):
|
def test_get_aggregate_node_cluster_creds(self):
|
||||||
|
|
||||||
self.library._have_cluster_creds = True
|
self.library._have_cluster_creds = True
|
||||||
@ -449,13 +485,11 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
self.library, '_get_aggregate_space',
|
self.library, '_get_aggregate_space',
|
||||||
mock.Mock(return_value=fake.AGGREGATE_CAPACITIES))
|
mock.Mock(return_value=fake.AGGREGATE_CAPACITIES))
|
||||||
self.library._have_cluster_creds = True
|
self.library._have_cluster_creds = True
|
||||||
|
self.library._revert_to_snapshot_support = True
|
||||||
self.library._cluster_info = fake.CLUSTER_INFO
|
self.library._cluster_info = fake.CLUSTER_INFO
|
||||||
self.library._ssc_stats = fake.SSC_INFO
|
self.library._ssc_stats = fake.SSC_INFO
|
||||||
self.library._perf_library.get_node_utilization_for_pool = (
|
self.library._perf_library.get_node_utilization_for_pool = (
|
||||||
mock.Mock(side_effect=[30.0, 42.0]))
|
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',
|
result = self.library._get_pools(filter_function='filter',
|
||||||
goodness_function='goodness')
|
goodness_function='goodness')
|
||||||
@ -468,13 +502,11 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
self.library, '_get_aggregate_space',
|
self.library, '_get_aggregate_space',
|
||||||
mock.Mock(return_value=fake.AGGREGATE_CAPACITIES_VSERVER_CREDS))
|
mock.Mock(return_value=fake.AGGREGATE_CAPACITIES_VSERVER_CREDS))
|
||||||
self.library._have_cluster_creds = False
|
self.library._have_cluster_creds = False
|
||||||
|
self.library._revert_to_snapshot_support = True
|
||||||
self.library._cluster_info = fake.CLUSTER_INFO
|
self.library._cluster_info = fake.CLUSTER_INFO
|
||||||
self.library._ssc_stats = fake.SSC_INFO_VSERVER_CREDS
|
self.library._ssc_stats = fake.SSC_INFO_VSERVER_CREDS
|
||||||
self.library._perf_library.get_node_utilization_for_pool = (
|
self.library._perf_library.get_node_utilization_for_pool = (
|
||||||
mock.Mock(side_effect=[50.0, 50.0]))
|
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()
|
result = self.library._get_pools()
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ import copy
|
|||||||
from manila.common import constants
|
from manila.common import constants
|
||||||
import manila.tests.share.drivers.netapp.fakes as na_fakes
|
import manila.tests.share.drivers.netapp.fakes as na_fakes
|
||||||
|
|
||||||
|
NO_SNAPRESTORE_LICENSE = '"SnapRestore" is not licensed in the cluster.'
|
||||||
CLUSTER_NAME = 'fake_cluster'
|
CLUSTER_NAME = 'fake_cluster'
|
||||||
CLUSTER_NAME_2 = 'fake_cluster_2'
|
CLUSTER_NAME_2 = 'fake_cluster_2'
|
||||||
BACKEND_NAME = 'fake_backend_name'
|
BACKEND_NAME = 'fake_backend_name'
|
||||||
|
@ -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.
|
Loading…
Reference in New Issue
Block a user