Merge "NetApp: Track SVM and Cluster scoped credentials" into stable/newton

This commit is contained in:
Jenkins 2017-04-04 17:42:07 +00:00 committed by Gerrit Code Review
commit 6c2575dc25
5 changed files with 190 additions and 17 deletions

View File

@ -1301,3 +1301,14 @@ SNAPMIRROR_INITIALIZE_RESULT = etree.XML("""
<result-status>succeeded</result-status>
</results>
""")
SYSTEM_NODE_GET_ITER_RESPONSE = etree.XML("""
<results status="passed">
<attributes-list>
<node-details-info>
<node>%s</node>
</node-details-info>
</attributes-list>
<num-records>1</num-records>
</results>
""" % NODE_NAME)

View File

@ -1673,6 +1673,18 @@ class NetAppCmodeClientTestCase(test.TestCase):
expected = {'compression': False, 'dedupe': False}
self.assertEqual(expected, result)
def test_get_flexvol_dedupe_info_api_insufficient_privileges(self):
api_error = netapp_api.NaApiError(code=netapp_api.EAPIPRIVILEGE)
self.mock_object(self.client,
'send_iter_request',
side_effect=api_error)
result = self.client.get_flexvol_dedupe_info(
fake_client.VOLUME_NAMES[0])
self.assertEqual({'compression': False, 'dedupe': False}, result)
def test_is_flexvol_mirrored(self):
api_response = netapp_api.NaElement(
@ -1920,6 +1932,70 @@ class NetAppCmodeClientTestCase(test.TestCase):
self.assertEqual({}, result)
def test_get_aggregate_api_not_found(self):
api_error = netapp_api.NaApiError(code=netapp_api.EAPINOTFOUND)
self.mock_object(self.client,
'send_iter_request',
side_effect=api_error)
result = self.client.get_aggregate(fake_client.VOLUME_AGGREGATE_NAME)
self.assertEqual({}, result)
def test_list_cluster_nodes(self):
api_response = netapp_api.NaElement(
fake_client.SYSTEM_NODE_GET_ITER_RESPONSE)
self.mock_object(self.client,
'send_request',
mock.Mock(return_value=api_response))
result = self.client.list_cluster_nodes()
self.assertListEqual([fake_client.NODE_NAME], result)
def test_list_cluster_nodes_not_found(self):
api_response = netapp_api.NaElement(fake_client.NO_RECORDS_RESPONSE)
self.mock_object(self.client,
'send_request',
mock.Mock(return_value=api_response))
result = self.client.list_cluster_nodes()
self.assertListEqual([], result)
def test_check_for_cluster_credentials(self):
self.mock_object(self.client,
'list_cluster_nodes',
mock.Mock(return_value=fake_client.NODE_NAMES))
result = self.client.check_for_cluster_credentials()
self.assertTrue(result)
def test_check_for_cluster_credentials_not_found(self):
api_error = netapp_api.NaApiError(code=netapp_api.EAPINOTFOUND)
self.mock_object(self.client,
'list_cluster_nodes',
side_effect=api_error)
result = self.client.check_for_cluster_credentials()
self.assertFalse(result)
def test_check_for_cluster_credentials_api_error(self):
self.mock_object(self.client,
'list_cluster_nodes',
self._mock_api_error())
self.assertRaises(netapp_api.NaApiError,
self.client.check_for_cluster_credentials)
@ddt.data({'types': {'FCAL'}, 'expected': ['FCAL']},
{'types': {'SATA', 'SSD'}, 'expected': ['SATA', 'SSD']},)
@ddt.unpack
@ -1949,6 +2025,18 @@ class NetAppCmodeClientTestCase(test.TestCase):
mock_get_aggregate_disk_types.assert_called_once_with(
fake_client.VOLUME_AGGREGATE_NAME)
def test_get_aggregate_disk_types_api_not_found(self):
api_error = netapp_api.NaApiError(code=netapp_api.EAPINOTFOUND)
self.mock_object(self.client,
'send_iter_request',
side_effect=api_error)
result = self.client.get_aggregate_disk_types(
fake_client.VOLUME_AGGREGATE_NAME)
self.assertIsNone(result)
def test_get_aggregate_disk_types_shared(self):
self.client.features.add_feature('ADVANCED_DISK_PARTITIONING')
@ -2175,6 +2263,16 @@ class NetAppCmodeClientTestCase(test.TestCase):
self.assertEqual({}, result)
def test_get_aggregate_capacity_api_not_found(self):
api_error = netapp_api.NaApiError(code=netapp_api.EAPINOTFOUND)
self.mock_object(self.client, 'send_request', side_effect=api_error)
result = self.client.get_aggregate_capacity(
fake_client.VOLUME_AGGREGATE_NAME)
self.assertEqual({}, result)
def test_get_performance_instance_uuids(self):
self.mock_send_request.return_value = netapp_api.NaElement(

View File

@ -31,6 +31,7 @@ from cinder.volume.drivers.netapp.dataontap import block_base
from cinder.volume.drivers.netapp.dataontap import block_cmode
from cinder.volume.drivers.netapp.dataontap.client import api as netapp_api
from cinder.volume.drivers.netapp.dataontap.client import client_base
from cinder.volume.drivers.netapp.dataontap.client import client_cmode
from cinder.volume.drivers.netapp.dataontap.performance import perf_cmode
from cinder.volume.drivers.netapp.dataontap.utils import data_motion
from cinder.volume.drivers.netapp.dataontap.utils import loopingcalls
@ -82,12 +83,16 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase):
config.netapp_vserver = 'openstack'
return config
@mock.patch.object(client_cmode.Client, 'check_for_cluster_credentials',
mock.MagicMock(return_value=False))
@mock.patch.object(perf_cmode, 'PerformanceCmodeLibrary', mock.Mock())
@mock.patch.object(client_base.Client, 'get_ontapi_version',
mock.MagicMock(return_value=(1, 20)))
@mock.patch.object(na_utils, 'check_flags')
@mock.patch.object(block_base.NetAppBlockStorageLibrary, 'do_setup')
def test_do_setup(self, super_do_setup, mock_check_flags):
self.zapi_client.check_for_cluster_credentials = mock.MagicMock(
return_value=True)
self.mock_object(client_base.Client, '_init_ssh_client')
self.mock_object(
config_utils, 'get_backend_configuration',
@ -353,6 +358,7 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase):
self.mock_object(self.library, 'get_replication_backend_names',
mock.Mock(return_value=replication_backends))
self.library.using_cluster_credentials = True
self.library.reserved_percentage = 5
self.library.max_over_subscription_ratio = 10
self.library.perf_library.get_node_utilization_for_pool = (

View File

@ -72,6 +72,8 @@ class NetAppBlockStorageCmodeLibrary(block_base.NetAppBlockStorageLibrary,
self.zapi_client = cmode_utils.get_client_for_backend(
self.failed_over_backend_name or self.backend_name)
self.vserver = self.zapi_client.vserver
self.using_cluster_credentials = \
self.zapi_client.check_for_cluster_credentials()
# Performance monitoring library
self.perf_library = perf_cmode.PerformanceCmodeLibrary(
@ -264,12 +266,18 @@ class NetAppBlockStorageCmodeLibrary(block_base.NetAppBlockStorageLibrary,
if not ssc:
return pools
# Get up-to-date node utilization metrics just once
self.perf_library.update_performance_cache(ssc)
# Utilization and performance metrics require cluster-scoped
# credentials
if self.using_cluster_credentials:
# Get up-to-date node utilization metrics just once
self.perf_library.update_performance_cache(ssc)
# Get up-to-date aggregate capacities just once
aggregates = self.ssc_library.get_ssc_aggregates()
aggr_capacities = self.zapi_client.get_aggregate_capacities(aggregates)
# Get up-to-date aggregate capacities just once
aggregates = self.ssc_library.get_ssc_aggregates()
aggr_capacities = self.zapi_client.get_aggregate_capacities(
aggregates)
else:
aggr_capacities = {}
for ssc_vol_name, ssc_vol_info in ssc.items():

View File

@ -20,6 +20,7 @@ import math
import re
from oslo_log import log as logging
from oslo_utils import excutils
from oslo_utils import units
import six
@ -752,6 +753,38 @@ class Client(client_base.Client):
return True
def list_cluster_nodes(self):
"""Get all available cluster nodes."""
api_args = {
'desired-attributes': {
'node-details-info': {
'node': None,
},
},
}
result = self.send_iter_request('system-node-get-iter', api_args)
nodes_info_list = result.get_child_by_name(
'attributes-list') or netapp_api.NaElement('none')
return [node_info.get_child_content('node') for node_info
in nodes_info_list.get_children()]
def check_for_cluster_credentials(self):
"""Checks whether cluster-scoped credentials are being used or not."""
try:
self.list_cluster_nodes()
# API succeeded, so definitely a cluster management LIF
return True
except netapp_api.NaApiError as e:
if e.code == netapp_api.EAPINOTFOUND:
LOG.debug('Not connected to cluster management LIF.')
else:
with excutils.save_and_reraise_exception():
msg = _LE('Failed to get the list of nodes.')
LOG.exception(msg)
return False
def get_operational_lif_addresses(self):
"""Gets the IP addresses of operational LIFs on the vserver."""
@ -990,9 +1023,14 @@ class Client(client_base.Client):
try:
result = self.send_iter_request('sis-get-iter', api_args)
except netapp_api.NaApiError:
msg = _LE('Failed to get dedupe info for volume %s.')
LOG.exception(msg, flexvol_name)
except netapp_api.NaApiError as e:
if e.code == netapp_api.EAPIPRIVILEGE:
LOG.debug('Dedupe info for volume %(name)s will not be '
'collected. This API requires cluster-scoped '
'credentials.', {'name': flexvol_name})
else:
msg = _LE('Failed to get dedupe info for volume %s.')
LOG.exception(msg, flexvol_name)
return {'compression': False, 'dedupe': False}
if self._get_record_count(result) != 1:
@ -1230,9 +1268,13 @@ class Client(client_base.Client):
try:
aggrs = self._get_aggregates(aggregate_names=[aggregate_name],
desired_attributes=desired_attributes)
except netapp_api.NaApiError:
msg = _LE('Failed to get info for aggregate %s.')
LOG.exception(msg, aggregate_name)
except netapp_api.NaApiError as e:
if e.code == netapp_api.EAPINOTFOUND:
LOG.debug('Aggregate info can only be collected with '
'cluster-scoped credentials.')
else:
msg = _LE('Failed to get info for aggregate %s.')
LOG.exception(msg, aggregate_name)
return {}
if len(aggrs) < 1:
@ -1302,9 +1344,13 @@ class Client(client_base.Client):
try:
result = self.send_iter_request(
'storage-disk-get-iter', api_args, enable_tunneling=False)
except netapp_api.NaApiError:
msg = _LE('Failed to get disk info for aggregate %s.')
LOG.exception(msg, aggregate_name)
except netapp_api.NaApiError as e:
if e.code == netapp_api.EAPINOTFOUND:
LOG.debug('Disk types can only be collected with '
'cluster scoped credentials.')
else:
msg = _LE('Failed to get disk info for aggregate %s.')
LOG.exception(msg, aggregate_name)
return disk_types
attributes_list = result.get_child_by_name(
@ -1350,9 +1396,13 @@ class Client(client_base.Client):
try:
aggrs = self._get_aggregates(aggregate_names=[aggregate_name],
desired_attributes=desired_attributes)
except netapp_api.NaApiError:
msg = _LE('Failed to get info for aggregate %s.')
LOG.exception(msg, aggregate_name)
except netapp_api.NaApiError as e:
if e.code == netapp_api.EAPINOTFOUND:
LOG.debug('Aggregate capacity can only be collected with '
'cluster scoped credentials.')
else:
msg = _LE('Failed to get info for aggregate %s.')
LOG.exception(msg, aggregate_name)
return {}
if len(aggrs) < 1: