From 7cc95f80549a45a245f988bcde9cc3ca013b8023 Mon Sep 17 00:00:00 2001 From: Clinton Knight Date: Tue, 19 Jul 2016 13:23:25 -0400 Subject: [PATCH] NetApp: Report hybrid aggregates in volume stats NetApp cDOT controllers can mix SSDs and spinning disks in the same aggregate, where the SSDs are used for a cache. This commit reports the hybrid aggregate attribute to the scheduler for each pool for use in extra specs matching. This commit also ensures that all aggregate values reported to the Cinder scheduler correctly include a vendor-specific prefix. Implements: blueprint netapp-report-cdot-hybrid-aggrs Change-Id: I8fbfbe3ffaad5fe89db03d2a4e567e9b35e59d5b --- .../drivers/netapp/dataontap/client/fakes.py | 37 +++++- .../dataontap/client/test_client_cmode.py | 123 +++++++++++++++--- .../dataontap/performance/test_perf_cmode.py | 6 +- .../netapp/dataontap/test_block_cmode.py | 6 +- .../netapp/dataontap/test_nfs_cmode.py | 6 +- .../drivers/netapp/dataontap/utils/fakes.py | 12 +- .../dataontap/utils/test_capabilities.py | 42 ++++-- .../drivers/netapp/dataontap/block_cmode.py | 4 +- .../netapp/dataontap/client/client_cmode.py | 71 ++++++---- .../drivers/netapp/dataontap/nfs_cmode.py | 4 +- .../dataontap/performance/perf_cmode.py | 4 +- .../netapp/dataontap/utils/capabilities.py | 21 +-- ...-netapp-cdot-drivers-f6afa9884cac4e86.yaml | 4 + 13 files changed, 254 insertions(+), 86 deletions(-) create mode 100644 releasenotes/notes/hybrid-aggregates-in-netapp-cdot-drivers-f6afa9884cac4e86.yaml diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/client/fakes.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/client/fakes.py index 634464fe35c..f6431071105 100644 --- a/cinder/tests/unit/volume/drivers/netapp/dataontap/client/fakes.py +++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/client/fakes.py @@ -622,7 +622,7 @@ AGGR_GET_NODE_RESPONSE = etree.XML(""" 'node': NODE_NAME, }) -AGGR_RAID_TYPE = 'raid_dp' +AGGREGATE_RAID_TYPE = 'raid_dp' AGGR_GET_ITER_SSC_RESPONSE = etree.XML(""" @@ -639,17 +639,19 @@ AGGR_GET_ITER_SSC_RESPONSE = etree.XML(""" %(raid)s + true %(aggr)s 1 -""" % {'aggr': VOLUME_AGGREGATE_NAME, 'raid': AGGR_RAID_TYPE}) +""" % {'aggr': VOLUME_AGGREGATE_NAME, 'raid': AGGREGATE_RAID_TYPE}) AGGR_INFO_SSC = { 'name': VOLUME_AGGREGATE_NAME, - 'raid-type': AGGR_RAID_TYPE, + 'raid-type': AGGREGATE_RAID_TYPE, + 'is-hybrid': True, } AGGR_SIZE_TOTAL = 107374182400 @@ -911,20 +913,41 @@ STORAGE_DISK_GET_ITER_RESPONSE_PAGE_3 = etree.XML(""" """) -AGGR_DISK_TYPE = 'FCAL' +AGGREGATE_DISK_TYPES = ['SATA', 'SSD'] STORAGE_DISK_GET_ITER_RESPONSE = etree.XML(""" cluster3-01:v5.19 - %s + %(type0)s + + + + cluster3-01:v5.20 + + %(type0)s + + + + cluster3-01:v5.20 + + %(type1)s + + + + cluster3-01:v5.20 + + %(type1)s - 1 + 4 -""" % AGGR_DISK_TYPE) +""" % { + 'type0': AGGREGATE_DISK_TYPES[0], + 'type1': AGGREGATE_DISK_TYPES[1], +}) SYSTEM_USER_CAPABILITY_GET_ITER_RESPONSE = etree.XML(""" diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode.py index 8ff81996c39..78df0d2ad98 100644 --- a/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode.py +++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode.py @@ -173,7 +173,7 @@ class NetAppCmodeClientTestCase(test.TestCase): max_page_length=10) num_records = result.get_child_content('num-records') - self.assertEqual('1', num_records) + self.assertEqual('4', num_records) args = copy.deepcopy(storage_disk_get_iter_args) args['max-records'] = 10 @@ -1681,6 +1681,7 @@ class NetAppCmodeClientTestCase(test.TestCase): 'aggregate-name': None, 'aggr-raid-attributes': { 'raid-type': None, + 'is-hybrid': None, }, }, } @@ -1692,6 +1693,7 @@ class NetAppCmodeClientTestCase(test.TestCase): expected = { 'name': fake_client.VOLUME_AGGREGATE_NAME, 'raid-type': 'raid_dp', + 'is-hybrid': True, } self.assertEqual(expected, result) @@ -1716,19 +1718,64 @@ class NetAppCmodeClientTestCase(test.TestCase): self.assertEqual({}, result) - def test_get_aggregate_disk_type(self): + @ddt.data({'types': {'FCAL'}, 'expected': ['FCAL']}, + {'types': {'SATA', 'SSD'}, 'expected': ['SATA', 'SSD']},) + @ddt.unpack + def test_get_aggregate_disk_types(self, types, expected): + + mock_get_aggregate_disk_types = self.mock_object( + self.client, '_get_aggregate_disk_types', + mock.Mock(return_value=types)) + + result = self.client.get_aggregate_disk_types( + fake_client.VOLUME_AGGREGATE_NAME) + + self.assertItemsEqual(expected, result) + mock_get_aggregate_disk_types.assert_called_once_with( + fake_client.VOLUME_AGGREGATE_NAME) + + def test_get_aggregate_disk_types_not_found(self): + + mock_get_aggregate_disk_types = self.mock_object( + self.client, '_get_aggregate_disk_types', + mock.Mock(return_value=set())) + + result = self.client.get_aggregate_disk_types( + fake_client.VOLUME_AGGREGATE_NAME) + + self.assertIsNone(result) + mock_get_aggregate_disk_types.assert_called_once_with( + fake_client.VOLUME_AGGREGATE_NAME) + + def test_get_aggregate_disk_types_shared(self): + + self.client.features.add_feature('ADVANCED_DISK_PARTITIONING') + mock_get_aggregate_disk_types = self.mock_object( + self.client, '_get_aggregate_disk_types', + mock.Mock(side_effect=[set(['SSD']), set(['SATA'])])) + + result = self.client.get_aggregate_disk_types( + fake_client.VOLUME_AGGREGATE_NAME) + + self.assertIsInstance(result, list) + self.assertItemsEqual(['SATA', 'SSD'], result) + mock_get_aggregate_disk_types.assert_has_calls([ + mock.call(fake_client.VOLUME_AGGREGATE_NAME), + mock.call(fake_client.VOLUME_AGGREGATE_NAME, shared=True), + ]) + + def test__get_aggregate_disk_types(self): api_response = netapp_api.NaElement( fake_client.STORAGE_DISK_GET_ITER_RESPONSE) self.mock_object(self.client, - 'send_request', + 'send_iter_request', mock.Mock(return_value=api_response)) - result = self.client.get_aggregate_disk_type( + result = self.client._get_aggregate_disk_types( fake_client.VOLUME_AGGREGATE_NAME) storage_disk_get_iter_args = { - 'max-records': 1, 'query': { 'storage-disk-info': { 'disk-raid-info': { @@ -1747,34 +1794,76 @@ class NetAppCmodeClientTestCase(test.TestCase): }, }, } - self.client.send_request.assert_called_once_with( + self.client.send_iter_request.assert_called_once_with( 'storage-disk-get-iter', storage_disk_get_iter_args, enable_tunneling=False) - self.assertEqual(fake_client.AGGR_DISK_TYPE, result) - @ddt.data(fake_client.NO_RECORDS_RESPONSE, fake_client.INVALID_RESPONSE) - def test_get_aggregate_disk_type_not_found(self, response): + expected = set(fake_client.AGGREGATE_DISK_TYPES) + self.assertEqual(expected, result) - api_response = netapp_api.NaElement(response) + def test__get_aggregate_disk_types_shared(self): + + api_response = netapp_api.NaElement( + fake_client.STORAGE_DISK_GET_ITER_RESPONSE) self.mock_object(self.client, - 'send_request', + 'send_iter_request', mock.Mock(return_value=api_response)) - result = self.client.get_aggregate_disk_type( + result = self.client._get_aggregate_disk_types( + fake_client.VOLUME_AGGREGATE_NAME, shared=True) + + storage_disk_get_iter_args = { + 'query': { + 'storage-disk-info': { + 'disk-raid-info': { + 'disk-shared-info': { + 'aggregate-list': { + 'shared-aggregate-info': { + 'aggregate-name': + fake_client.VOLUME_AGGREGATE_NAME, + }, + }, + }, + }, + }, + }, + 'desired-attributes': { + 'storage-disk-info': { + 'disk-raid-info': { + 'effective-disk-type': None, + }, + }, + }, + } + self.client.send_iter_request.assert_called_once_with( + 'storage-disk-get-iter', storage_disk_get_iter_args, + enable_tunneling=False) + + expected = set(fake_client.AGGREGATE_DISK_TYPES) + self.assertEqual(expected, result) + + def test__get_aggregate_disk_types_not_found(self): + + api_response = netapp_api.NaElement(fake_client.NO_RECORDS_RESPONSE) + self.mock_object(self.client, + 'send_iter_request', + mock.Mock(return_value=api_response)) + + result = self.client._get_aggregate_disk_types( fake_client.VOLUME_AGGREGATE_NAME) - self.assertEqual('unknown', result) + self.assertEqual(set(), result) - def test_get_aggregate_disk_type_api_error(self): + def test__get_aggregate_disk_types_api_error(self): self.mock_object(self.client, - 'send_request', + 'send_iter_request', mock.Mock(side_effect=self._mock_api_error())) - result = self.client.get_aggregate_disk_type( + result = self.client._get_aggregate_disk_types( fake_client.VOLUME_AGGREGATE_NAME) - self.assertEqual('unknown', result) + self.assertEqual(set([]), result) def test_get_aggregate_capacities(self): diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/performance/test_perf_cmode.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/performance/test_perf_cmode.py index 7a80579a87a..da52f356a22 100644 --- a/cinder/tests/unit/volume/drivers/netapp/dataontap/performance/test_perf_cmode.py +++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/performance/test_perf_cmode.py @@ -45,13 +45,13 @@ class PerformanceCmodeLibraryTestCase(test.TestCase): self.fake_volumes = { 'pool1': { - 'aggregate': 'aggr1', + 'netapp_aggregate': 'aggr1', }, 'pool2': { - 'aggregate': 'aggr2', + 'netapp_aggregate': 'aggr2', }, 'pool3': { - 'aggregate': 'aggr2', + 'netapp_aggregate': 'aggr2', }, } diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_cmode.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_cmode.py index d13106d4410..335ae3df9f7 100644 --- a/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_cmode.py +++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_cmode.py @@ -302,7 +302,7 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase): 'netapp_compression': 'false', 'netapp_mirrored': 'false', 'netapp_dedup': 'true', - 'aggregate': 'aggr1', + 'netapp_aggregate': 'aggr1', 'netapp_raid_type': 'raid_dp', 'netapp_disk_type': 'SSD', }, @@ -349,7 +349,7 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase): 'total_capacity_gb': 10.0, 'free_capacity_gb': 2.0, 'provisioned_capacity_gb': 8.0, - 'aggregate_used_percent': 45, + 'netapp_aggregate_used_percent': 45, 'utilization': 30.0, 'filter_function': 'filter', 'goodness_function': 'goodness', @@ -359,7 +359,7 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase): 'netapp_compression': 'false', 'netapp_mirrored': 'false', 'netapp_dedup': 'true', - 'aggregate': 'aggr1', + 'netapp_aggregate': 'aggr1', 'netapp_raid_type': 'raid_dp', 'netapp_disk_type': 'SSD', }] diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_cmode.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_cmode.py index 293ddffd99f..1a0a0469a9e 100644 --- a/cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_cmode.py +++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_cmode.py @@ -93,7 +93,7 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase): 'netapp_compression': 'false', 'netapp_mirrored': 'false', 'netapp_dedup': 'true', - 'aggregate': 'aggr1', + 'netapp_aggregate': 'aggr1', 'netapp_raid_type': 'raid_dp', 'netapp_disk_type': 'SSD', }, @@ -146,7 +146,7 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase): 'total_capacity_gb': total_capacity_gb, 'free_capacity_gb': free_capacity_gb, 'provisioned_capacity_gb': provisioned_capacity_gb, - 'aggregate_used_percent': 45, + 'netapp_aggregate_used_percent': 45, 'utilization': 30.0, 'filter_function': 'filter', 'goodness_function': 'goodness', @@ -156,7 +156,7 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase): 'netapp_compression': 'false', 'netapp_mirrored': 'false', 'netapp_dedup': 'true', - 'aggregate': 'aggr1', + 'netapp_aggregate': 'aggr1', 'netapp_raid_type': 'raid_dp', 'netapp_disk_type': 'SSD', }] diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/utils/fakes.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/utils/fakes.py index fad7bf7bf9a..5d2abceaafe 100644 --- a/cinder/tests/unit/volume/drivers/netapp/dataontap/utils/fakes.py +++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/utils/fakes.py @@ -30,24 +30,26 @@ SSC = { 'thick_provisioning_support': True, 'thin_provisioning_support': False, 'netapp_thin_provisioned': 'false', - 'aggregate': 'aggr1', + 'netapp_aggregate': 'aggr1', 'netapp_compression': 'false', 'netapp_dedup': 'true', 'netapp_mirrored': 'false', 'netapp_raid_type': 'raid_dp', 'netapp_disk_type': 'SSD', + 'netapp_hybrid_aggregate': False, 'pool_name': 'volume1', }, 'volume2': { 'thick_provisioning_support': False, 'thin_provisioning_support': True, 'netapp_thin_provisioned': 'true', - 'aggregate': 'aggr2', + 'netapp_aggregate': 'aggr2', 'netapp_compression': 'true', 'netapp_dedup': 'true', 'netapp_mirrored': 'true', 'netapp_raid_type': 'raid_dp', 'netapp_disk_type': 'FCAL', + 'netapp_hybrid_aggregate': True, 'pool_name': 'volume2', }, } @@ -57,13 +59,13 @@ SSC_FLEXVOL_INFO = { 'thick_provisioning_support': True, 'thin_provisioning_support': False, 'netapp_thin_provisioned': 'false', - 'aggregate': 'aggr1', + 'netapp_aggregate': 'aggr1', }, 'volume2': { 'thick_provisioning_support': False, 'thin_provisioning_support': True, 'netapp_thin_provisioned': 'true', - 'aggregate': 'aggr2', + 'netapp_aggregate': 'aggr2', }, } @@ -91,9 +93,11 @@ SSC_AGGREGATE_INFO = { 'volume1': { 'netapp_disk_type': 'SSD', 'netapp_raid_type': 'raid_dp', + 'netapp_hybrid_aggregate': False, }, 'volume2': { 'netapp_disk_type': 'FCAL', 'netapp_raid_type': 'raid_dp', + 'netapp_hybrid_aggregate': True, }, } diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/utils/test_capabilities.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/utils/test_capabilities.py index c59f4063d85..fbb82a2ac9b 100644 --- a/cinder/tests/unit/volume/drivers/netapp/dataontap/utils/test_capabilities.py +++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/utils/test_capabilities.py @@ -171,7 +171,7 @@ class CapabilitiesLibraryTestCase(test.TestCase): 'netapp_thin_provisioned': 'true', 'thick_provisioning_support': False, 'thin_provisioning_support': True, - 'aggregate': 'fake_aggr1', + 'netapp_aggregate': 'fake_aggr1', } self.assertEqual(expected, result) self.zapi_client.get_flexvol.assert_called_once_with( @@ -198,7 +198,7 @@ class CapabilitiesLibraryTestCase(test.TestCase): 'netapp_thin_provisioned': 'false', 'thick_provisioning_support': lun_space_guarantee, 'thin_provisioning_support': not lun_space_guarantee, - 'aggregate': 'fake_aggr1', + 'netapp_aggregate': 'fake_aggr1', } self.assertEqual(expected, result) self.zapi_client.get_flexvol.assert_called_once_with( @@ -223,7 +223,7 @@ class CapabilitiesLibraryTestCase(test.TestCase): 'netapp_thin_provisioned': 'true', 'thick_provisioning_support': False, 'thin_provisioning_support': True, - 'aggregate': 'fake_aggr1', + 'netapp_aggregate': 'fake_aggr1', } self.assertEqual(expected, result) self.zapi_client.get_flexvol.assert_called_once_with( @@ -251,7 +251,7 @@ class CapabilitiesLibraryTestCase(test.TestCase): 'netapp_thin_provisioned': 'false', 'thick_provisioning_support': not nfs_sparsed_volumes, 'thin_provisioning_support': nfs_sparsed_volumes, - 'aggregate': 'fake_aggr1', + 'netapp_aggregate': 'fake_aggr1', } self.assertEqual(expected, result) self.zapi_client.get_flexvol.assert_called_once_with( @@ -291,25 +291,45 @@ class CapabilitiesLibraryTestCase(test.TestCase): def test_get_ssc_aggregate_info(self): - self.mock_object( - self.ssc_library.zapi_client, 'get_aggregate_disk_type', - mock.Mock(return_value=fake_client.AGGR_DISK_TYPE)) self.mock_object( self.ssc_library.zapi_client, 'get_aggregate', mock.Mock(return_value=fake_client.AGGR_INFO_SSC)) + self.mock_object( + self.ssc_library.zapi_client, 'get_aggregate_disk_types', + mock.Mock(return_value=fake_client.AGGREGATE_DISK_TYPES)) result = self.ssc_library._get_ssc_aggregate_info( fake_client.VOLUME_AGGREGATE_NAME) expected = { - 'netapp_disk_type': fake_client.AGGR_DISK_TYPE, - 'netapp_raid_type': fake_client.AGGR_RAID_TYPE, + 'netapp_disk_type': fake_client.AGGREGATE_DISK_TYPES, + 'netapp_raid_type': fake_client.AGGREGATE_RAID_TYPE, + 'netapp_hybrid_aggregate': 'true', } self.assertEqual(expected, result) - self.zapi_client.get_aggregate_disk_type.assert_called_once_with( - fake_client.VOLUME_AGGREGATE_NAME) self.zapi_client.get_aggregate.assert_called_once_with( fake_client.VOLUME_AGGREGATE_NAME) + self.zapi_client.get_aggregate_disk_types.assert_called_once_with( + fake_client.VOLUME_AGGREGATE_NAME) + + def test_get_ssc_aggregate_info_not_found(self): + + self.mock_object( + self.ssc_library.zapi_client, 'get_aggregate', + mock.Mock(return_value={})) + self.mock_object( + self.ssc_library.zapi_client, 'get_aggregate_disk_types', + mock.Mock(return_value=None)) + + result = self.ssc_library._get_ssc_aggregate_info( + fake_client.VOLUME_AGGREGATE_NAME) + + expected = { + 'netapp_disk_type': None, + 'netapp_raid_type': None, + 'netapp_hybrid_aggregate': None, + } + self.assertEqual(expected, result) def test_get_matching_flexvols_for_extra_specs(self): diff --git a/cinder/volume/drivers/netapp/dataontap/block_cmode.py b/cinder/volume/drivers/netapp/dataontap/block_cmode.py index a770dc9912c..3be46c59f7b 100644 --- a/cinder/volume/drivers/netapp/dataontap/block_cmode.py +++ b/cinder/volume/drivers/netapp/dataontap/block_cmode.py @@ -251,9 +251,9 @@ class NetAppBlockStorageCmodeLibrary(block_base.NetAppBlockStorageLibrary): pool['provisioned_capacity_gb'] = round( pool['total_capacity_gb'] - pool['free_capacity_gb'], 2) - aggregate_name = ssc_vol_info.get('aggregate') + aggregate_name = ssc_vol_info.get('netapp_aggregate') aggr_capacity = aggr_capacities.get(aggregate_name, {}) - pool['aggregate_used_percent'] = aggr_capacity.get( + pool['netapp_aggregate_used_percent'] = aggr_capacity.get( 'percent-used', 0) # Add utilization data diff --git a/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py b/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py index 10f157028bc..d6f34c3368e 100644 --- a/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py +++ b/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py @@ -67,6 +67,8 @@ class Client(client_base.Client): self.features.add_feature('FAST_CLONE_DELETE', supported=ontapi_1_30) self.features.add_feature('SYSTEM_CONSTITUENT_METRICS', supported=ontapi_1_30) + self.features.add_feature('ADVANCED_DISK_PARTITIONING', + supported=ontapi_1_30) self.features.add_feature('BACKUP_CLONE_PARAM', supported=ontapi_1_100) def _invoke_vserver_api(self, na_element, vserver): @@ -1093,6 +1095,7 @@ class Client(client_base.Client): 'aggregate-name': None, 'aggr-raid-attributes': { 'raid-type': None, + 'is-hybrid': None, }, }, } @@ -1115,25 +1118,50 @@ class Client(client_base.Client): aggregate = { 'name': aggr_attributes.get_child_content('aggregate-name'), 'raid-type': aggr_raid_attrs.get_child_content('raid-type'), + 'is-hybrid': strutils.bool_from_string( + aggr_raid_attrs.get_child_content('is-hybrid')), } return aggregate - def get_aggregate_disk_type(self, aggregate_name): - """Get the disk type of an aggregate.""" + def get_aggregate_disk_types(self, aggregate_name): + """Get the disk type(s) of an aggregate.""" - # Note(cknight): Only get 1 disk, since apart from hybrid - # aggregates all disks must be the same type. - api_args = { - 'max-records': 1, - 'query': { - 'storage-disk-info': { - 'disk-raid-info': { - 'disk-aggregate-info': { + disk_types = set() + disk_types.update(self._get_aggregate_disk_types(aggregate_name)) + if self.features.ADVANCED_DISK_PARTITIONING: + disk_types.update(self._get_aggregate_disk_types(aggregate_name, + shared=True)) + + return list(disk_types) if disk_types else None + + def _get_aggregate_disk_types(self, aggregate_name, shared=False): + """Get the disk type(s) of an aggregate (may be a list).""" + + disk_types = set() + + if shared: + disk_raid_info = { + 'disk-shared-info': { + 'aggregate-list': { + 'shared-aggregate-info': { 'aggregate-name': aggregate_name, }, }, }, + } + else: + disk_raid_info = { + 'disk-aggregate-info': { + 'aggregate-name': aggregate_name, + }, + } + + api_args = { + 'query': { + 'storage-disk-info': { + 'disk-raid-info': disk_raid_info, + }, }, 'desired-attributes': { 'storage-disk-info': { @@ -1143,29 +1171,28 @@ class Client(client_base.Client): }, }, } + try: - result = self.send_request('storage-disk-get-iter', api_args, - enable_tunneling=False) + 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) - return 'unknown' - - if self._get_record_count(result) != 1: - return 'unknown' + return disk_types attributes_list = result.get_child_by_name( 'attributes-list') or netapp_api.NaElement('none') for storage_disk_info in attributes_list.get_children(): - disk_raid_info = storage_disk_info.get_child_by_name( - 'disk-raid-info') or netapp_api.NaElement('none') - disk_type = disk_raid_info.get_child_content( - 'effective-disk-type') or 'unknown' - return disk_type + disk_raid_info = storage_disk_info.get_child_by_name( + 'disk-raid-info') or netapp_api.NaElement('none') + disk_type = disk_raid_info.get_child_content( + 'effective-disk-type') + if disk_type: + disk_types.add(disk_type) - return 'unknown' + return disk_types def get_aggregate_capacities(self, aggregate_names): """Gets capacity info for multiple aggregates.""" diff --git a/cinder/volume/drivers/netapp/dataontap/nfs_cmode.py b/cinder/volume/drivers/netapp/dataontap/nfs_cmode.py index b4ceeb4b98f..001eee42d36 100644 --- a/cinder/volume/drivers/netapp/dataontap/nfs_cmode.py +++ b/cinder/volume/drivers/netapp/dataontap/nfs_cmode.py @@ -208,9 +208,9 @@ class NetAppCmodeNfsDriver(nfs_base.NetAppNfsDriver): capacity = self._get_share_capacity_info(nfs_share) pool.update(capacity) - aggregate_name = ssc_vol_info.get('aggregate') + aggregate_name = ssc_vol_info.get('netapp_aggregate') aggr_capacity = aggr_capacities.get(aggregate_name, {}) - pool['aggregate_used_percent'] = aggr_capacity.get( + pool['netapp_aggregate_used_percent'] = aggr_capacity.get( 'percent-used', 0) # Add utilization data diff --git a/cinder/volume/drivers/netapp/dataontap/performance/perf_cmode.py b/cinder/volume/drivers/netapp/dataontap/performance/perf_cmode.py index 16a276c07b6..e85c83d1169 100644 --- a/cinder/volume/drivers/netapp/dataontap/performance/perf_cmode.py +++ b/cinder/volume/drivers/netapp/dataontap/performance/perf_cmode.py @@ -97,7 +97,7 @@ class PerformanceCmodeLibrary(perf_base.PerformanceLibrary): # Update pool utilization map atomically pool_utilization = {} for pool_name, pool_info in ssc_pools.items(): - aggr_name = pool_info.get('aggregate', 'unknown') + aggr_name = pool_info.get('netapp_aggregate', 'unknown') node_name = aggr_node_map.get(aggr_name) if node_name: pool_utilization[pool_name] = node_utilization.get( @@ -118,7 +118,7 @@ class PerformanceCmodeLibrary(perf_base.PerformanceLibrary): aggr_names = set() for pool_name, pool_info in ssc_pools.items(): - aggr_names.add(pool_info.get('aggregate')) + aggr_names.add(pool_info.get('netapp_aggregate')) return aggr_names def _get_nodes_for_aggregates(self, aggr_names): diff --git a/cinder/volume/drivers/netapp/dataontap/utils/capabilities.py b/cinder/volume/drivers/netapp/dataontap/utils/capabilities.py index b4e7941f5e7..a5fcb796250 100644 --- a/cinder/volume/drivers/netapp/dataontap/utils/capabilities.py +++ b/cinder/volume/drivers/netapp/dataontap/utils/capabilities.py @@ -98,8 +98,8 @@ class CapabilitiesLibrary(object): aggregates = set() for __, flexvol_info in self.ssc.items(): - if 'aggregate' in flexvol_info: - aggregates.add(flexvol_info['aggregate']) + if 'netapp_aggregate' in flexvol_info: + aggregates.add(flexvol_info['netapp_aggregate']) return list(aggregates) def update_ssc(self, flexvol_map): @@ -126,7 +126,7 @@ class CapabilitiesLibrary(object): ssc_volume.update(self._get_ssc_mirror_info(flexvol_name)) # Get aggregate info - aggregate_name = ssc_volume.get('aggregate') + aggregate_name = ssc_volume.get('netapp_aggregate') ssc_volume.update(self._get_ssc_aggregate_info(aggregate_name)) ssc[flexvol_name] = ssc_volume @@ -147,7 +147,7 @@ class CapabilitiesLibrary(object): 'netapp_thin_provisioned': six.text_type(not netapp_thick).lower(), 'thick_provisioning_support': thick, 'thin_provisioning_support': not thick, - 'aggregate': volume_info.get('aggregate'), + 'netapp_aggregate': volume_info.get('aggregate'), } def _get_thick_provisioning_support(self, netapp_thick): @@ -190,14 +190,15 @@ class CapabilitiesLibrary(object): def _get_ssc_aggregate_info(self, aggregate_name): """Gather aggregate info and recast into SSC-style volume stats.""" - disk_type = self.zapi_client.get_aggregate_disk_type(aggregate_name) - aggr_info = self.zapi_client.get_aggregate(aggregate_name) - - raid_type = aggr_info.get('raid-type') + aggregate = self.zapi_client.get_aggregate(aggregate_name) + hybrid = (six.text_type(aggregate.get('is-hybrid')).lower() + if 'is-hybrid' in aggregate else None) + disk_types = self.zapi_client.get_aggregate_disk_types(aggregate_name) return { - 'netapp_disk_type': disk_type, - 'netapp_raid_type': raid_type, + 'netapp_raid_type': aggregate.get('raid-type'), + 'netapp_hybrid_aggregate': hybrid, + 'netapp_disk_type': disk_types, } def get_matching_flexvols_for_extra_specs(self, extra_specs): diff --git a/releasenotes/notes/hybrid-aggregates-in-netapp-cdot-drivers-f6afa9884cac4e86.yaml b/releasenotes/notes/hybrid-aggregates-in-netapp-cdot-drivers-f6afa9884cac4e86.yaml new file mode 100644 index 00000000000..b3bfba0f238 --- /dev/null +++ b/releasenotes/notes/hybrid-aggregates-in-netapp-cdot-drivers-f6afa9884cac4e86.yaml @@ -0,0 +1,4 @@ +--- +features: + - Add support for hybrid aggregates to the NetApp cDOT drivers. +