NetApp cDOT driver should not report untenable pools
The NetApp cDOT driver now explicitly filters root aggregates from the pools reported to the manila scheduler if the driver is operating with cluster credentials. Change-Id: I659edada559e50d2332790025c65fae265a27c3d Closes-Bug: #1624526
This commit is contained in:
parent
16c522bf5e
commit
eb2d9640e2
manila
share/drivers/netapp/dataontap
tests/share/drivers/netapp/dataontap
releasenotes/notes
@ -444,7 +444,51 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
||||
return sorted(ports, key=sort_key, reverse=True)
|
||||
|
||||
@na_utils.trace
|
||||
def list_aggregates(self):
|
||||
def list_root_aggregates(self):
|
||||
"""Get names of all aggregates that contain node root volumes."""
|
||||
|
||||
desired_attributes = {
|
||||
'aggr-attributes': {
|
||||
'aggregate-name': None,
|
||||
'aggr-raid-attributes': {
|
||||
'has-local-root': None,
|
||||
'has-partner-root': None,
|
||||
},
|
||||
},
|
||||
}
|
||||
aggrs = self._get_aggregates(desired_attributes=desired_attributes)
|
||||
|
||||
root_aggregates = []
|
||||
for aggr in aggrs:
|
||||
aggr_name = aggr.get_child_content('aggregate-name')
|
||||
aggr_raid_attrs = aggr.get_child_by_name('aggr-raid-attributes')
|
||||
|
||||
local_root = strutils.bool_from_string(
|
||||
aggr_raid_attrs.get_child_content('has-local-root'))
|
||||
partner_root = strutils.bool_from_string(
|
||||
aggr_raid_attrs.get_child_content('has-partner-root'))
|
||||
|
||||
if local_root or partner_root:
|
||||
root_aggregates.append(aggr_name)
|
||||
|
||||
return root_aggregates
|
||||
|
||||
@na_utils.trace
|
||||
def list_non_root_aggregates(self):
|
||||
"""Get names of all aggregates that don't contain node root volumes."""
|
||||
|
||||
query = {
|
||||
'aggr-attributes': {
|
||||
'aggr-raid-attributes': {
|
||||
'has-local-root': 'false',
|
||||
'has-partner-root': 'false',
|
||||
}
|
||||
},
|
||||
}
|
||||
return self._list_aggregates(query=query)
|
||||
|
||||
@na_utils.trace
|
||||
def _list_aggregates(self, query=None):
|
||||
"""Get names of all aggregates."""
|
||||
try:
|
||||
api_args = {
|
||||
@ -454,6 +498,8 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
||||
},
|
||||
},
|
||||
}
|
||||
if query:
|
||||
api_args['query'] = query
|
||||
result = self.send_iter_request('aggr-get-iter', api_args)
|
||||
aggr_list = result.get_child_by_name(
|
||||
'attributes-list').get_children()
|
||||
|
@ -100,7 +100,7 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
|
||||
@na_utils.trace
|
||||
def _find_matching_aggregates(self):
|
||||
"""Find all aggregates match pattern."""
|
||||
aggregate_names = self._client.list_aggregates()
|
||||
aggregate_names = self._client.list_non_root_aggregates()
|
||||
pattern = self.configuration.netapp_aggregate_name_search_pattern
|
||||
return [aggr_name for aggr_name in aggregate_names
|
||||
if re.match(pattern, aggr_name)]
|
||||
|
@ -115,9 +115,15 @@ class NetAppCmodeSingleSVMFileStorageLibrary(
|
||||
"""Find all aggregates match pattern."""
|
||||
vserver_client = self._get_api_client(vserver=self._vserver)
|
||||
aggregate_names = vserver_client.list_vserver_aggregates()
|
||||
|
||||
root_aggregate_names = []
|
||||
if self._have_cluster_creds:
|
||||
root_aggregate_names = self._client.list_root_aggregates()
|
||||
|
||||
pattern = self.configuration.netapp_aggregate_name_search_pattern
|
||||
return [aggr_name for aggr_name in aggregate_names
|
||||
if re.match(pattern, aggr_name)]
|
||||
if re.match(pattern, aggr_name) and
|
||||
aggr_name not in root_aggregate_names]
|
||||
|
||||
@na_utils.trace
|
||||
def get_network_allocations_number(self):
|
||||
|
@ -38,6 +38,7 @@ VSERVER_NAME_2 = 'fake_vserver_2'
|
||||
ADMIN_VSERVER_NAME = 'fake_admin_vserver'
|
||||
NODE_VSERVER_NAME = 'fake_node_vserver'
|
||||
NFS_VERSIONS = ['nfs3', 'nfs4.0']
|
||||
ROOT_AGGREGATE_NAMES = ('root_aggr1', 'root_aggr2')
|
||||
ROOT_VOLUME_AGGREGATE_NAME = 'fake_root_aggr'
|
||||
ROOT_VOLUME_NAME = 'fake_root_volume'
|
||||
SHARE_AGGREGATE_NAME = 'fake_aggr1'
|
||||
@ -791,34 +792,21 @@ AGGR_GET_NAMES_RESPONSE = etree.XML("""
|
||||
<attributes-list>
|
||||
<aggr-attributes>
|
||||
<aggr-raid-attributes>
|
||||
<plexes>
|
||||
<plex-attributes>
|
||||
<plex-name>/%(aggr1)s/plex0</plex-name>
|
||||
<raidgroups>
|
||||
<raidgroup-attributes>
|
||||
<raidgroup-name>/%(aggr1)s/plex0/rg0</raidgroup-name>
|
||||
</raidgroup-attributes>
|
||||
</raidgroups>
|
||||
</plex-attributes>
|
||||
</plexes>
|
||||
</aggr-raid-attributes>
|
||||
<aggregate-name>%(root1)s</aggregate-name>
|
||||
</aggr-attributes>
|
||||
<aggr-attributes>
|
||||
<aggr-raid-attributes>
|
||||
</aggr-raid-attributes>
|
||||
<aggregate-name>%(root2)s</aggregate-name>
|
||||
</aggr-attributes>
|
||||
<aggr-attributes>
|
||||
<aggr-raid-attributes>
|
||||
</aggr-raid-attributes>
|
||||
<aggregate-name>%(aggr1)s</aggregate-name>
|
||||
</aggr-attributes>
|
||||
<aggr-attributes>
|
||||
<aggr-raid-attributes>
|
||||
<plexes>
|
||||
<plex-attributes>
|
||||
<plex-name>/%(aggr2)s/plex0</plex-name>
|
||||
<raidgroups>
|
||||
<raidgroup-attributes>
|
||||
<raidgroup-name>/%(aggr2)s/plex0/rg0</raidgroup-name>
|
||||
</raidgroup-attributes>
|
||||
<raidgroup-attributes>
|
||||
<raidgroup-name>/%(aggr2)s/plex0/rg1</raidgroup-name>
|
||||
</raidgroup-attributes>
|
||||
</raidgroups>
|
||||
</plex-attributes>
|
||||
</plexes>
|
||||
</aggr-raid-attributes>
|
||||
<aggregate-name>%(aggr2)s</aggregate-name>
|
||||
</aggr-attributes>
|
||||
@ -826,6 +814,8 @@ AGGR_GET_NAMES_RESPONSE = etree.XML("""
|
||||
<num-records>2</num-records>
|
||||
</results>
|
||||
""" % {
|
||||
'root1': ROOT_AGGREGATE_NAMES[0],
|
||||
'root2': ROOT_AGGREGATE_NAMES[1],
|
||||
'aggr1': SHARE_AGGREGATE_NAMES[0],
|
||||
'aggr2': SHARE_AGGREGATE_NAMES[1],
|
||||
})
|
||||
@ -1268,6 +1258,72 @@ AGGR_GET_ITER_SSC_RESPONSE = etree.XML("""
|
||||
</results>
|
||||
""" % {'aggr1': SHARE_AGGREGATE_NAMES[0]})
|
||||
|
||||
AGGR_GET_ITER_ROOT_AGGR_RESPONSE = etree.XML("""
|
||||
<results status="passed">
|
||||
<attributes-list>
|
||||
<aggr-attributes>
|
||||
<aggr-raid-attributes>
|
||||
<has-local-root>true</has-local-root>
|
||||
<has-partner-root>false</has-partner-root>
|
||||
</aggr-raid-attributes>
|
||||
<aggregate-name>%(root1)s</aggregate-name>
|
||||
</aggr-attributes>
|
||||
<aggr-attributes>
|
||||
<aggr-raid-attributes>
|
||||
<has-local-root>true</has-local-root>
|
||||
<has-partner-root>false</has-partner-root>
|
||||
</aggr-raid-attributes>
|
||||
<aggregate-name>%(root2)s</aggregate-name>
|
||||
</aggr-attributes>
|
||||
<aggr-attributes>
|
||||
<aggr-raid-attributes>
|
||||
<has-local-root>false</has-local-root>
|
||||
<has-partner-root>false</has-partner-root>
|
||||
</aggr-raid-attributes>
|
||||
<aggregate-name>%(aggr1)s</aggregate-name>
|
||||
</aggr-attributes>
|
||||
<aggr-attributes>
|
||||
<aggr-raid-attributes>
|
||||
<has-local-root>false</has-local-root>
|
||||
<has-partner-root>false</has-partner-root>
|
||||
</aggr-raid-attributes>
|
||||
<aggregate-name>%(aggr2)s</aggregate-name>
|
||||
</aggr-attributes>
|
||||
</attributes-list>
|
||||
<num-records>6</num-records>
|
||||
</results>
|
||||
""" % {
|
||||
'root1': ROOT_AGGREGATE_NAMES[0],
|
||||
'root2': ROOT_AGGREGATE_NAMES[1],
|
||||
'aggr1': SHARE_AGGREGATE_NAMES[0],
|
||||
'aggr2': SHARE_AGGREGATE_NAMES[1],
|
||||
})
|
||||
|
||||
AGGR_GET_ITER_NON_ROOT_AGGR_RESPONSE = etree.XML("""
|
||||
<results status="passed">
|
||||
<attributes-list>
|
||||
<aggr-attributes>
|
||||
<aggr-raid-attributes>
|
||||
<has-local-root>false</has-local-root>
|
||||
<has-partner-root>false</has-partner-root>
|
||||
</aggr-raid-attributes>
|
||||
<aggregate-name>%(aggr1)s</aggregate-name>
|
||||
</aggr-attributes>
|
||||
<aggr-attributes>
|
||||
<aggr-raid-attributes>
|
||||
<has-local-root>false</has-local-root>
|
||||
<has-partner-root>false</has-partner-root>
|
||||
</aggr-raid-attributes>
|
||||
<aggregate-name>%(aggr2)s</aggregate-name>
|
||||
</aggr-attributes>
|
||||
</attributes-list>
|
||||
<num-records>6</num-records>
|
||||
</results>
|
||||
""" % {
|
||||
'aggr1': SHARE_AGGREGATE_NAMES[0],
|
||||
'aggr2': SHARE_AGGREGATE_NAMES[1],
|
||||
})
|
||||
|
||||
VOLUME_GET_NAME_RESPONSE = etree.XML("""
|
||||
<results status="passed">
|
||||
<attributes-list>
|
||||
|
@ -796,16 +796,80 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
||||
|
||||
self.assertSequenceEqual(fake.SORTED_PORTS_ALL_SPEEDS, result)
|
||||
|
||||
def test_list_root_aggregates(self):
|
||||
|
||||
api_response = netapp_api.NaElement(
|
||||
fake.AGGR_GET_ITER_ROOT_AGGR_RESPONSE)
|
||||
self.mock_object(self.client,
|
||||
'send_iter_request',
|
||||
mock.Mock(return_value=api_response))
|
||||
|
||||
result = self.client.list_root_aggregates()
|
||||
|
||||
aggr_get_iter_args = {
|
||||
'desired-attributes': {
|
||||
'aggr-attributes': {
|
||||
'aggregate-name': None,
|
||||
'aggr-raid-attributes': {
|
||||
'has-local-root': None,
|
||||
'has-partner-root': None,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
self.assertSequenceEqual(fake.ROOT_AGGREGATE_NAMES, result)
|
||||
self.client.send_iter_request.assert_has_calls([
|
||||
mock.call('aggr-get-iter', aggr_get_iter_args)])
|
||||
|
||||
def test_list_non_root_aggregates(self):
|
||||
|
||||
api_response = netapp_api.NaElement(
|
||||
fake.AGGR_GET_ITER_NON_ROOT_AGGR_RESPONSE)
|
||||
self.mock_object(self.client,
|
||||
'send_iter_request',
|
||||
mock.Mock(return_value=api_response))
|
||||
|
||||
result = self.client.list_non_root_aggregates()
|
||||
|
||||
aggr_get_iter_args = {
|
||||
'query': {
|
||||
'aggr-attributes': {
|
||||
'aggr-raid-attributes': {
|
||||
'has-local-root': 'false',
|
||||
'has-partner-root': 'false',
|
||||
}
|
||||
},
|
||||
},
|
||||
'desired-attributes': {
|
||||
'aggr-attributes': {
|
||||
'aggregate-name': None,
|
||||
},
|
||||
},
|
||||
}
|
||||
self.assertSequenceEqual(fake.SHARE_AGGREGATE_NAMES, result)
|
||||
self.client.send_iter_request.assert_has_calls([
|
||||
mock.call('aggr-get-iter', aggr_get_iter_args)])
|
||||
|
||||
def test_list_aggregates(self):
|
||||
|
||||
api_response = netapp_api.NaElement(fake.AGGR_GET_NAMES_RESPONSE)
|
||||
self.mock_object(self.client,
|
||||
'send_request',
|
||||
'send_iter_request',
|
||||
mock.Mock(return_value=api_response))
|
||||
|
||||
result = self.client.list_aggregates()
|
||||
result = self.client._list_aggregates()
|
||||
|
||||
self.assertSequenceEqual(fake.SHARE_AGGREGATE_NAMES, result)
|
||||
aggr_get_iter_args = {
|
||||
'desired-attributes': {
|
||||
'aggr-attributes': {
|
||||
'aggregate-name': None,
|
||||
},
|
||||
},
|
||||
}
|
||||
self.assertSequenceEqual(
|
||||
fake.ROOT_AGGREGATE_NAMES + fake.SHARE_AGGREGATE_NAMES, result)
|
||||
self.client.send_iter_request.assert_has_calls([
|
||||
mock.call('aggr-get-iter', aggr_get_iter_args)])
|
||||
|
||||
def test_list_aggregates_not_found(self):
|
||||
|
||||
@ -815,7 +879,7 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
||||
mock.Mock(return_value=api_response))
|
||||
|
||||
self.assertRaises(exception.NetAppException,
|
||||
self.client.list_aggregates)
|
||||
self.client._list_aggregates)
|
||||
|
||||
def test_list_vserver_aggregates(self):
|
||||
|
||||
|
@ -186,14 +186,16 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
|
||||
def test_find_matching_aggregates(self):
|
||||
|
||||
self.mock_object(self.client,
|
||||
'list_aggregates',
|
||||
mock.Mock(return_value=fake.AGGREGATES))
|
||||
|
||||
mock_list_non_root_aggregates = self.mock_object(
|
||||
self.client, 'list_non_root_aggregates',
|
||||
mock.Mock(return_value=fake.AGGREGATES))
|
||||
self.library.configuration.netapp_aggregate_name_search_pattern = (
|
||||
'.*_aggr_1')
|
||||
|
||||
result = self.library._find_matching_aggregates()
|
||||
|
||||
self.assertListEqual([fake.AGGREGATES[0]], result)
|
||||
mock_list_non_root_aggregates.assert_called_once_with()
|
||||
|
||||
def test_setup_server(self):
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
Unit tests for the NetApp Data ONTAP cDOT single-SVM storage driver library.
|
||||
"""
|
||||
|
||||
import ddt
|
||||
import mock
|
||||
from oslo_log import log
|
||||
|
||||
@ -26,6 +27,7 @@ from manila import test
|
||||
import manila.tests.share.drivers.netapp.dataontap.fakes as fake
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
@ -164,19 +166,32 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
self.assertTrue(mock_vserver_client.prune_deleted_snapshots.called)
|
||||
self.assertTrue(mock_super.called)
|
||||
|
||||
def test_find_matching_aggregates(self):
|
||||
@ddt.data(True, False)
|
||||
def test_find_matching_aggregates(self, have_cluster_creds):
|
||||
|
||||
self.library._have_cluster_creds = have_cluster_creds
|
||||
aggregates = fake.AGGREGATES + fake.ROOT_AGGREGATES
|
||||
mock_vserver_client = mock.Mock()
|
||||
mock_vserver_client.list_vserver_aggregates.return_value = (
|
||||
fake.AGGREGATES)
|
||||
mock_vserver_client.list_vserver_aggregates.return_value = aggregates
|
||||
self.mock_object(self.library,
|
||||
'_get_api_client',
|
||||
mock.Mock(return_value=mock_vserver_client))
|
||||
mock_client = mock.Mock()
|
||||
mock_client.list_root_aggregates.return_value = fake.ROOT_AGGREGATES
|
||||
self.library._client = mock_client
|
||||
|
||||
self.library.configuration.netapp_aggregate_name_search_pattern = (
|
||||
'.*_aggr_1')
|
||||
|
||||
result = self.library._find_matching_aggregates()
|
||||
self.assertListEqual([fake.AGGREGATES[0]], result)
|
||||
|
||||
if have_cluster_creds:
|
||||
self.assertListEqual([fake.AGGREGATES[0]], result)
|
||||
mock_client.list_root_aggregates.assert_called_once_with()
|
||||
else:
|
||||
self.assertListEqual([fake.AGGREGATES[0], fake.ROOT_AGGREGATES[0]],
|
||||
result)
|
||||
self.assertFalse(mock_client.list_root_aggregates.called)
|
||||
|
||||
def test_get_network_allocations_number(self):
|
||||
self.assertEqual(0, self.library.get_network_allocations_number())
|
||||
|
@ -54,6 +54,7 @@ FREE_CAPACITY = 10000000000
|
||||
TOTAL_CAPACITY = 20000000000
|
||||
AGGREGATE = 'manila_aggr_1'
|
||||
AGGREGATES = ('manila_aggr_1', 'manila_aggr_2')
|
||||
ROOT_AGGREGATES = ('root_aggr_1', 'root_aggr_2')
|
||||
ROOT_VOLUME_AGGREGATE = 'manila1'
|
||||
ROOT_VOLUME = 'root'
|
||||
CLUSTER_NODE = 'cluster1_01'
|
||||
|
6
releasenotes/notes/bug-1624526-netapp-cdot-filter-root-aggregates-c30ac5064d530b86.yaml
Normal file
6
releasenotes/notes/bug-1624526-netapp-cdot-filter-root-aggregates-c30ac5064d530b86.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
fixes:
|
||||
- The NetApp cDOT driver now explicitly filters root aggregates
|
||||
from the pools reported to the manila scheduler if the driver
|
||||
is operating with cluster credentials.
|
||||
|
Loading…
x
Reference in New Issue
Block a user