From 48d922cf625c079c8338bf90a3d17f849df0c6b5 Mon Sep 17 00:00:00 2001 From: Jayaanand Borra Date: Wed, 30 Aug 2023 00:21:25 +0530 Subject: [PATCH] [NetApp] LUN space allocation support Space allocation is an important NetApp driver specific feature. This needs to be set when the cinder volume is created. This is not related to thin/thick provisioning feature of cinder volumes.It is independent of that. It enables ONTAP to reclaim space automatically when host deletes data.This helps ONTAP and host to see the actual space correctly when the host deletes data. It also helps to keep a LUN (cinder volume) online when the LUN (cinder volume) in ontap runs out of space and containing volume (in ONTAP) cannot automatically grow more space. User can configure it by using volume type extra spec. By default Space allocation value is disabled for ONTAP LUN netapp:space_allocation: " True" # to enable space allocation netapp:space_allocation: " False" # to disable space allocation Blueprint: netapp-space-allocation-support Change-Id: Ib7072f3093067ecd8ad84e396aaecec8f15c49ba --- .../drivers/netapp/dataontap/client/fakes.py | 6 ++ .../dataontap/client/test_client_base.py | 77 +++++++++++---- .../client/test_client_cmode_rest.py | 4 + .../volume/drivers/netapp/dataontap/fakes.py | 13 ++- .../netapp/dataontap/test_block_base.py | 98 ++++++++++++++++++- .../drivers/netapp/dataontap/block_base.py | 18 +++- .../netapp/dataontap/client/client_base.py | 4 + .../netapp/dataontap/client/client_cmode.py | 2 + .../dataontap/client/client_cmode_rest.py | 10 +- ...e-allocation-support-36a26aecc8fe1500.yaml | 9 ++ 10 files changed, 215 insertions(+), 26 deletions(-) create mode 100644 releasenotes/notes/netapp-space-allocation-support-36a26aecc8fe1500.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 5b535de104e..07dfbfcc1e3 100644 --- a/cinder/tests/unit/volume/drivers/netapp/dataontap/client/fakes.py +++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/client/fakes.py @@ -2347,6 +2347,9 @@ LUN_GET_ITER_RESULT = [ 'OsType': LUN_GET_ITER_REST['records'][0]['os_type'], 'SpaceReserved': LUN_GET_ITER_REST['records'][0]['space']['guarantee']['requested'], + 'SpaceAllocated': + LUN_GET_ITER_REST['records'][0]['space'] + ['scsi_thin_provisioning_support_enabled'], 'UUID': LUN_GET_ITER_REST['records'][0]['uuid'], }, { @@ -2360,6 +2363,9 @@ LUN_GET_ITER_RESULT = [ 'OsType': LUN_GET_ITER_REST['records'][1]['os_type'], 'SpaceReserved': LUN_GET_ITER_REST['records'][1]['space']['guarantee']['requested'], + 'SpaceAllocated': + LUN_GET_ITER_REST['records'][1]['space'] + ['scsi_thin_provisioning_support_enabled'], 'UUID': LUN_GET_ITER_REST['records'][1]['uuid'], }, ] diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_base.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_base.py index 3dc3873ffa1..930722c71df 100644 --- a/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_base.py +++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_base.py @@ -55,7 +55,8 @@ class NetAppBaseClientTestCase(test.TestCase): self.fake_volume = six.text_type(uuid.uuid4()) self.fake_lun = six.text_type(uuid.uuid4()) self.fake_size = '1024' - self.fake_metadata = {'OsType': 'linux', 'SpaceReserved': 'true'} + self.fake_metadata = {'OsType': 'linux', 'SpaceReserved': 'true', + 'SpaceAllocated': 'true'} self.mock_send_request = self.mock_object( self.client.connection, 'send_request') @@ -89,14 +90,23 @@ class NetAppBaseClientTestCase(test.TestCase): self.assertIsNone(self.client.check_is_naelement(element)) self.assertRaises(ValueError, self.client.check_is_naelement, None) - @ddt.data({'ontap_version': (9, 4, 0), 'space_reservation': 'true'}, - {'ontap_version': (9, 4, 0), 'space_reservation': 'false'}, - {'ontap_version': (9, 6, 0), 'space_reservation': 'true'}, - {'ontap_version': (9, 6, 0), 'space_reservation': 'false'}) + @ddt.data({'ontap_version': (9, 4, 0), + 'space_reservation': 'true', + 'space_alloc': 'true'}, + {'ontap_version': (9, 4, 0), + 'space_reservation': 'false', + 'space_alloc': 'false'}, + {'ontap_version': (9, 6, 0), + 'space_reservation': 'true', + 'space_alloc': 'true'}, + {'ontap_version': (9, 6, 0), + 'space_reservation': 'false', + 'space_alloc': 'false'}, ) @ddt.unpack - def test_create_lun(self, ontap_version, space_reservation): + def test_create_lun(self, ontap_version, space_reservation, space_alloc): expected_path = '/vol/%s/%s' % (self.fake_volume, self.fake_lun) self.fake_metadata['SpaceReserved'] = space_reservation + self.fake_metadata['SpaceAllocated'] = space_alloc expected_space_reservation = space_reservation self.mock_object(self.client, 'get_ontap_version', return_value=ontap_version) @@ -127,7 +137,9 @@ class NetAppBaseClientTestCase(test.TestCase): 'size': initial_size, 'ostype': self.fake_metadata['OsType'], 'space-reservation-enabled': - expected_space_reservation}) + expected_space_reservation, + 'space-allocation-enabled': + space_alloc}) self.connection.invoke_successfully.assert_called_with( mock.ANY, True) @@ -141,15 +153,25 @@ class NetAppBaseClientTestCase(test.TestCase): else: mock_set_space_reservation.assert_not_called() - @ddt.data({'ontap_version': (9, 4, 0), 'space_reservation': 'true'}, - {'ontap_version': (9, 4, 0), 'space_reservation': 'false'}, - {'ontap_version': (9, 6, 0), 'space_reservation': 'true'}, - {'ontap_version': (9, 6, 0), 'space_reservation': 'false'}) + @ddt.data({'ontap_version': (9, 4, 0), + 'space_reservation': 'true', + 'space_alloc': 'true'}, + {'ontap_version': (9, 4, 0), + 'space_reservation': 'false', + 'space_alloc': 'false'}, + {'ontap_version': (9, 6, 0), + 'space_reservation': 'true', + 'space_alloc': 'true'}, + {'ontap_version': (9, 6, 0), + 'space_reservation': 'false', + 'space_alloc': 'false'}, ) @ddt.unpack - def test_create_lun_exact_size(self, ontap_version, space_reservation): + def test_create_lun_exact_size(self, ontap_version, + space_reservation, space_alloc): expected_path = '/vol/%s/%s' % (self.fake_volume, self.fake_lun) self.connection.get_api_version.return_value = (1, 110) self.fake_metadata['SpaceReserved'] = space_reservation + self.fake_metadata['SpaceAllocated'] = space_alloc expected_space_reservation = self.fake_metadata['SpaceReserved'] self.mock_object(self.client, 'get_ontap_version', return_value=ontap_version) @@ -181,7 +203,9 @@ class NetAppBaseClientTestCase(test.TestCase): 'ostype': self.fake_metadata['OsType'], 'use-exact-size': 'true', 'space-reservation-enabled': - expected_space_reservation}) + expected_space_reservation, + 'space-allocation-enabled': + space_alloc}) self.connection.invoke_successfully.assert_called_with( mock.ANY, True) @@ -195,18 +219,27 @@ class NetAppBaseClientTestCase(test.TestCase): else: mock_set_space_reservation.assert_not_called() - @ddt.data({'ontap_version': (9, 4, 0), 'space_reservation': 'true'}, - {'ontap_version': (9, 4, 0), 'space_reservation': 'false'}, - {'ontap_version': (9, 6, 0), 'space_reservation': 'true'}, - {'ontap_version': (9, 6, 0), 'space_reservation': 'false'}) + @ddt.data({'ontap_version': (9, 4, 0), + 'space_reservation': 'true', + 'space_alloc': 'true'}, + {'ontap_version': (9, 4, 0), + 'space_reservation': 'false', + 'space_alloc': 'false'}, + {'ontap_version': (9, 6, 0), + 'space_reservation': 'true', + 'space_alloc': 'true'}, + {'ontap_version': (9, 6, 0), + 'space_reservation': 'false', + 'space_alloc': 'false'}, ) @ddt.unpack def test_create_lun_with_qos_policy_group_name( - self, ontap_version, space_reservation): + self, ontap_version, space_reservation, space_alloc): expected_path = '/vol/%s/%s' % (self.fake_volume, self.fake_lun) expected_qos_group_name = 'qos_1' mock_request = mock.Mock() self.fake_metadata['SpaceReserved'] = space_reservation + self.fake_metadata['SpaceAllocated'] = space_alloc expected_space_reservation = self.fake_metadata['SpaceReserved'] self.mock_object(self.client, 'get_ontap_version', return_value=ontap_version) @@ -237,9 +270,11 @@ class NetAppBaseClientTestCase(test.TestCase): mock_create_node.assert_called_with( 'lun-create-by-size', **{'path': expected_path, 'size': initial_size, - 'ostype': self.fake_metadata['OsType'], - 'space-reservation-enabled': - expected_space_reservation}) + 'ostype': self.fake_metadata['OsType'], + 'space-reservation-enabled': + expected_space_reservation, + 'space-allocation-enabled': + space_alloc}) mock_request.add_new_child.assert_called_with( 'qos-policy-group', expected_qos_group_name) self.connection.invoke_successfully.assert_called_with( diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode_rest.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode_rest.py index b72cda4ea0e..262ddc21acc 100644 --- a/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode_rest.py +++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode_rest.py @@ -854,6 +854,7 @@ class NetAppRestCmodeClientTestCase(test.TestCase): 'uuid': fake.UUID1, 'fields': 'svm.name,location.volume.name,space.size,' 'location.qtree.name,name,os_type,' + 'space.scsi_thin_provisioning_support_enabled,' 'space.guarantee.requested,uuid' } @@ -884,6 +885,7 @@ class NetAppRestCmodeClientTestCase(test.TestCase): 'name': path, 'fields': 'svm.name,location.volume.name,space.size,' 'location.qtree.name,name,os_type,' + 'space.scsi_thin_provisioning_support_enabled,' 'space.guarantee.requested,uuid' } @@ -1678,6 +1680,8 @@ class NetAppRestCmodeClientTestCase(test.TestCase): 'space.size': str(initial_size), 'os_type': metadata['OsType'], 'space.guarantee.requested': metadata['SpaceReserved'], + 'space.scsi_thin_provisioning_support_enabled': + metadata['SpaceAllocated'], 'qos_policy.name': fake.QOS_POLICY_GROUP_NAME } diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/fakes.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/fakes.py index f5e50047682..47e1bf11ae0 100644 --- a/cinder/tests/unit/volume/drivers/netapp/dataontap/fakes.py +++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/fakes.py @@ -64,10 +64,19 @@ JOB_UUID = 'fb132b04-6422-43ce-9451-ee819f0131a4' LUN_METADATA = { 'OsType': None, 'SpaceReserved': 'true', + 'SpaceAllocated': 'false', 'Path': PATH, 'Qtree': None, 'Volume': POOL_NAME, } +LUN_METADATA_WITH_SPACE_ALLOCATION = { + 'OsType': None, + 'SpaceReserved': 'true', + 'Path': PATH, + 'SpaceAllocated': 'true', + 'Qtree': None, + 'Volume': POOL_NAME, +} NAMESPACE_METADATA = { 'OsType': None, 'Path': PATH_NAMESPACE, @@ -239,6 +248,7 @@ ISCSI_VOLUME = { 'name': 'fake_volume', 'id': 'fake_id', 'provider_auth': 'fake provider auth', + 'provider_location': 'iscsi:/dummy_path' } ISCSI_LUN = {'name': ISCSI_VOLUME, 'lun_id': 42} @@ -250,6 +260,7 @@ ISCSI_CONNECTION_PROPERTIES = { 'auth_method': 'fake_method', 'auth_password': 'auth', 'auth_username': 'provider', + 'discard': True, 'discovery_auth_method': 'fake_method', 'discovery_auth_username': 'provider', 'discovery_auth_password': 'auth', @@ -289,7 +300,7 @@ IGROUP1 = {'initiator-group-os-type': 'linux', 'initiator-group-name': IGROUP1_NAME} QOS_SPECS = {} -EXTRA_SPECS = {} +EXTRA_SPECS = {'netapp:space_allocation': ' True'} MAX_THROUGHPUT = '21734278B/s' MIN_IOPS = '256iops' MAX_IOPS = '512iops' diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_base.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_base.py index f57391bbd51..2a4807651c7 100644 --- a/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_base.py +++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_base.py @@ -136,22 +136,97 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase): self.library._create_lun.assert_called_once_with( fake.POOL_NAME, fake.LUN_NAME, volume_size_in_bytes, - fake.LUN_METADATA, fake.QOS_POLICY_GROUP_NAME, False) + fake.LUN_METADATA, + fake.QOS_POLICY_GROUP_NAME, False) self.library._get_volume_model_update.assert_called_once_with( fake.VOLUME) self.assertEqual( 0, self.library. _mark_qos_policy_group_for_deletion.call_count) self.assertEqual(0, block_base.LOG.error.call_count) + def test_create_volume_space_allocation_extra_spec_false(self): + volume_size_in_bytes = int(fake.SIZE) * units.Gi + self.mock_object(na_utils, 'get_volume_extra_specs', + return_value={ + 'netapp:space_allocation': ' False' + } + ) + self.mock_object(na_utils, 'log_extra_spec_warnings') + self.mock_object(block_base, 'LOG') + self.mock_object(volume_utils, 'extract_host', + return_value=fake.POOL_NAME) + self.mock_object(self.library, '_setup_qos_for_volume', + return_value=fake.QOS_POLICY_GROUP_INFO) + self.mock_object(self.library, '_create_lun') + self.mock_object(self.library, '_create_lun_handle') + self.mock_object(self.library, '_add_lun_to_table') + self.mock_object(self.library, '_mark_qos_policy_group_for_deletion') + self.mock_object(self.library, '_get_volume_model_update') + + self.library.create_volume(fake.VOLUME) + + self.library._create_lun.assert_called_once_with( + fake.POOL_NAME, fake.LUN_NAME, volume_size_in_bytes, + fake.LUN_METADATA, + fake.QOS_POLICY_GROUP_NAME, False) + self.library._get_volume_model_update.assert_called_once_with( + fake.VOLUME) + self.assertEqual( + 0, self.library._mark_qos_policy_group_for_deletion.call_count) + self.assertEqual(0, block_base.LOG.error.call_count) + + def test_create_volume_space_allocation_extra_spec_true(self): + volume_size_in_bytes = int(fake.SIZE) * units.Gi + self.mock_object(na_utils, 'get_volume_extra_specs', + return_value={ + 'netapp:space_allocation': ' True' + } + ) + self.mock_object(na_utils, 'log_extra_spec_warnings') + self.mock_object(block_base, 'LOG') + self.mock_object(volume_utils, 'extract_host', + return_value=fake.POOL_NAME) + self.mock_object(self.library, '_setup_qos_for_volume', + return_value=fake.QOS_POLICY_GROUP_INFO) + self.mock_object(self.library, '_create_lun') + self.mock_object(self.library, '_create_lun_handle') + self.mock_object(self.library, '_add_lun_to_table') + self.mock_object(self.library, '_mark_qos_policy_group_for_deletion') + self.mock_object(self.library, '_get_volume_model_update') + + self.library.create_volume(fake.VOLUME) + + self.library._create_lun.assert_called_once_with( + fake.POOL_NAME, fake.LUN_NAME, volume_size_in_bytes, + fake.LUN_METADATA_WITH_SPACE_ALLOCATION, + fake.QOS_POLICY_GROUP_NAME, False) + self.library._get_volume_model_update.assert_called_once_with( + fake.VOLUME) + self.assertEqual( + 0, self.library._mark_qos_policy_group_for_deletion.call_count) + self.assertEqual(0, block_base.LOG.error.call_count) + def test_create_volume_no_pool(self): self.mock_object(volume_utils, 'extract_host', return_value=None) self.assertRaises(exception.InvalidHost, self.library.create_volume, fake.VOLUME) + def test_space_allocation_exception_path(self): + self.mock_object(block_base, 'LOG') + self.mock_object(na_utils, 'get_volume_extra_specs', + return_value={'netapp:space_allocation': 'xyz'}) + self.mock_object(self.library, '_setup_qos_for_volume', + return_value=fake.QOS_POLICY_GROUP_INFO) + self.mock_object(self.library, '_create_lun', side_effect=Exception) + self.mock_object(self.library, '_mark_qos_policy_group_for_deletion') + self.assertRaises(exception.VolumeBackendAPIException, + self.library.create_volume, fake.VOLUME) + def test_create_volume_exception_path(self): self.mock_object(block_base, 'LOG') - self.mock_object(na_utils, 'get_volume_extra_specs') + self.mock_object(na_utils, 'get_volume_extra_specs', + return_value={}) self.mock_object(self.library, '_setup_qos_for_volume', return_value=fake.QOS_POLICY_GROUP_INFO) self.mock_object(self.library, '_create_lun', side_effect=Exception) @@ -767,6 +842,9 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase): self.mock_object(block_base.NetAppBlockStorageLibrary, '_get_targets_from_list', return_value=target_details_list) + self.mock_object(block_base.NetAppBlockStorageLibrary, + '_is_space_alloc_enabled', + return_value=True) self.zapi_client.get_iscsi_service_details.return_value = ( fake.ISCSI_SERVICE_IQN) self.mock_object(na_utils, @@ -796,6 +874,10 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase): fake.ISCSI_CONNECTION_PROPERTIES['data'] ['discovery_auth_username'], target_info['data']['discovery_auth_username']) + self.assertEqual( + fake.ISCSI_CONNECTION_PROPERTIES['data'] + ['discard'], + target_info['data']['discard']) self.assertEqual(fake.ISCSI_CONNECTION_PROPERTIES, target_info) block_base.NetAppBlockStorageLibrary._map_lun.assert_called_once_with( @@ -815,6 +897,9 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase): self.zapi_client.get_iscsi_target_details.return_value = None self.mock_object(block_base.NetAppBlockStorageLibrary, '_get_targets_from_list') + self.mock_object(block_base.NetAppBlockStorageLibrary, + '_is_space_alloc_enabled', + return_value=True) self.mock_object(na_utils, 'get_iscsi_connection_properties', return_value=fake.ISCSI_CONNECTION_PROPERTIES) @@ -826,6 +911,9 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase): self.assertEqual( 0, block_base.NetAppBlockStorageLibrary ._get_targets_from_list.call_count) + self.assertEqual( + 0, block_base.NetAppBlockStorageLibrary + ._is_space_alloc_enabled.call_count) self.assertEqual( 0, self.zapi_client.get_iscsi_service_details.call_count) self.assertEqual( @@ -840,6 +928,9 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase): self.mock_object(block_base.NetAppBlockStorageLibrary, '_get_targets_from_list', return_value=None) + self.mock_object(block_base.NetAppBlockStorageLibrary, + '_is_space_alloc_enabled', + return_value=True) self.mock_object(na_utils, 'get_iscsi_connection_properties') self.assertRaises(exception.VolumeBackendAPIException, @@ -848,6 +939,9 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase): self.assertEqual(0, self.zapi_client .get_iscsi_service_details.call_count) + self.assertEqual(0, + block_base.NetAppBlockStorageLibrary + ._is_space_alloc_enabled.call_count) self.assertEqual(0, na_utils.get_iscsi_connection_properties .call_count) diff --git a/cinder/volume/drivers/netapp/dataontap/block_base.py b/cinder/volume/drivers/netapp/dataontap/block_base.py index f0a8649edab..c058443f148 100644 --- a/cinder/volume/drivers/netapp/dataontap/block_base.py +++ b/cinder/volume/drivers/netapp/dataontap/block_base.py @@ -224,12 +224,17 @@ class NetAppBlockStorageLibrary(object): extra_specs = na_utils.get_volume_extra_specs(volume) + space_allocation = volume_utils.is_boolean_str( + extra_specs.get('netapp:space_allocation') + ) + LOG.debug('create_volume space_allocation %r', space_allocation) lun_name = volume['name'] size = int(volume['size']) * units.Gi metadata = {'OsType': self.lun_ostype, 'SpaceReserved': self.lun_space_reservation, + 'SpaceAllocated': str(space_allocation).lower(), 'Path': '/vol/%s/%s' % (pool_name, lun_name)} qos_policy_group_info = self._setup_qos_for_volume(volume, extra_specs) @@ -712,6 +717,16 @@ class NetAppBlockStorageLibrary(object): " post clone resize LUN %s.", seg[-1]) LOG.error("Exception details: %s", e) + def _is_space_alloc_enabled(self, path): + """Gets space allocation details for the LUN.""" + LOG.debug("Getting LUN space allocation enabled.") + lun_infos = self.zapi_client.get_lun_by_args(path=path) + if not lun_infos: + seg = path.split('/') + msg = _('Failure getting LUN info for %s' % seg[-1]) + raise exception.VolumeBackendAPIException(data=msg) + return lun_infos[0]['SpaceAllocated'] == "true" + def _get_lun_block_count(self, path): """Gets block counts for the LUN.""" LOG.debug("Getting LUN block count.") @@ -844,6 +859,7 @@ class NetAppBlockStorageLibrary(object): """ initiator_name = connector['initiator'] + lun_path = volume['provider_location'].split(':')[1] name = volume['name'] lun_id = self._map_lun(name, [initiator_name], 'iscsi', None) @@ -874,7 +890,7 @@ class NetAppBlockStorageLibrary(object): properties = na_utils.get_iscsi_connection_properties(lun_id, volume, iqn, addresses, ports) - + properties['discard'] = self._is_space_alloc_enabled(lun_path) if self.configuration.use_chap_auth: chap_username, chap_password = self._configure_chap(initiator_name) self._add_chap_properties(properties, chap_username, chap_password) diff --git a/cinder/volume/drivers/netapp/dataontap/client/client_base.py b/cinder/volume/drivers/netapp/dataontap/client/client_base.py index 65cdf98189c..b2fadab33da 100644 --- a/cinder/volume/drivers/netapp/dataontap/client/client_base.py +++ b/cinder/volume/drivers/netapp/dataontap/client/client_base.py @@ -130,6 +130,10 @@ class Client(object): params = {'path': path, 'size': str(initial_size), 'ostype': metadata['OsType'], 'space-reservation-enabled': space_reservation} + + if "SpaceAllocated" in metadata: + params['space-allocation-enabled'] = metadata['SpaceAllocated'] + version = self.get_ontapi_version() if version >= (1, 110): params['use-exact-size'] = 'true' diff --git a/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py b/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py index a35af9d53de..177779a3a74 100644 --- a/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py +++ b/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py @@ -545,6 +545,8 @@ class Client(client_base.Client): meta_dict['OsType'] = lun.get_child_content('multiprotocol-type') meta_dict['SpaceReserved'] = \ lun.get_child_content('is-space-reservation-enabled') + meta_dict['SpaceAllocated'] = \ + lun.get_child_content('is-space-alloc-enabled') meta_dict['UUID'] = lun.get_child_content('uuid') meta_dict['BlockSize'] = lun.get_child_content('block-size') return meta_dict diff --git a/cinder/volume/drivers/netapp/dataontap/client/client_cmode_rest.py b/cinder/volume/drivers/netapp/dataontap/client/client_cmode_rest.py index db5a2371ea9..9953ec6b159 100644 --- a/cinder/volume/drivers/netapp/dataontap/client/client_cmode_rest.py +++ b/cinder/volume/drivers/netapp/dataontap/client/client_cmode_rest.py @@ -663,6 +663,7 @@ class RestClient(object): 'svm.name': self.vserver, 'fields': 'svm.name,location.volume.name,space.size,' 'location.qtree.name,name,os_type,' + 'space.scsi_thin_provisioning_support_enabled,' 'space.guarantee.requested,uuid' } @@ -683,6 +684,8 @@ class RestClient(object): lun_info['Path'] = lun['name'] lun_info['OsType'] = lun['os_type'] lun_info['SpaceReserved'] = lun['space']['guarantee']['requested'] + lun_info['SpaceAllocated'] = \ + lun['space']['scsi_thin_provisioning_support_enabled'] lun_info['UUID'] = lun['uuid'] lun_list.append(lun_info) @@ -695,6 +698,7 @@ class RestClient(object): query = { 'fields': 'svm.name,location.volume.name,space.size,' 'location.qtree.name,name,os_type,' + 'space.scsi_thin_provisioning_support_enabled,' 'space.guarantee.requested,uuid' } @@ -723,6 +727,8 @@ class RestClient(object): lun_info['Path'] = lun['name'] lun_info['OsType'] = lun['os_type'] lun_info['SpaceReserved'] = lun['space']['guarantee']['requested'] + lun_info['SpaceAllocated'] = \ + lun['space']['scsi_thin_provisioning_support_enabled'] lun_info['UUID'] = lun['uuid'] # NOTE(nahimsouza): Currently, ONTAP REST API does not have the @@ -1305,13 +1311,15 @@ class RestClient(object): path = f'/vol/{volume_name}/{lun_name}' space_reservation = metadata['SpaceReserved'] + space_allocation = metadata['SpaceAllocated'] initial_size = size body = { 'name': path, 'space.size': str(initial_size), 'os_type': metadata['OsType'], - 'space.guarantee.requested': space_reservation + 'space.guarantee.requested': space_reservation, + 'space.scsi_thin_provisioning_support_enabled': space_allocation } if qos_policy_group_name: diff --git a/releasenotes/notes/netapp-space-allocation-support-36a26aecc8fe1500.yaml b/releasenotes/notes/netapp-space-allocation-support-36a26aecc8fe1500.yaml new file mode 100644 index 00000000000..7ae0e3c94ba --- /dev/null +++ b/releasenotes/notes/netapp-space-allocation-support-36a26aecc8fe1500.yaml @@ -0,0 +1,9 @@ +features: + - | + NetApp iSCSI/FCP drivers: NetApp space allocation feature allows ONTAP + and host to see the actual space correctly when host deletes data. + It also notifies the host when the LUN cannot accept write data due + to lack of space on the volume, and makes the LUN read-only + (rather than going offline). This feature can be enabled or + disabled on cinder volumes by using volume type extra specs with + the ``netapp:space_allocation`` property. \ No newline at end of file