From 43538613ee615c31b2ec577505597a601048cdec Mon Sep 17 00:00:00 2001 From: jayaanand borra Date: Mon, 29 Jul 2024 02:44:22 -0400 Subject: [PATCH] [NetApp] Custom storage efficiency policy support for Manila share This change introduce a new extra spec netapp:efficiency_policy where the user can specify a pre-created NetApp efficiency policy from share located share-server. During share creation, User specified efficiency policy can be applied to the FlexVol/FlexGroup volume that corresponds to the Manila Share. Blueprint: manila-netapp-efficiency-policy Change-Id: I1ebc1b8ac6d70c4f525593d0fc75aa0cae2b22bf --- .../netapp/dataontap/client/client_cmode.py | 50 ++++-- .../dataontap/client/client_cmode_rest.py | 41 +++-- .../netapp/dataontap/cluster_mode/lib_base.py | 6 +- .../drivers/netapp/dataontap/client/fakes.py | 1 + .../dataontap/client/test_client_cmode.py | 142 ++++++++++++++---- .../client/test_client_cmode_rest.py | 82 +++++++++- .../dataontap/cluster_mode/test_lib_base.py | 15 +- .../share/drivers/netapp/dataontap/fakes.py | 5 + ...ge-efficiency-policy-5fa0b2b15901bf93.yaml | 10 ++ 9 files changed, 292 insertions(+), 60 deletions(-) create mode 100644 releasenotes/notes/manila-netapp-storage-efficiency-policy-5fa0b2b15901bf93.yaml diff --git a/manila/share/drivers/netapp/dataontap/client/client_cmode.py b/manila/share/drivers/netapp/dataontap/client/client_cmode.py index 5969a04fe9..da9b9954b8 100644 --- a/manila/share/drivers/netapp/dataontap/client/client_cmode.py +++ b/manila/share/drivers/netapp/dataontap/client/client_cmode.py @@ -2238,9 +2238,11 @@ class NetAppCmodeClient(client_base.NetAppBaseClient): self.send_request('volume-create', api_args) - self.update_volume_efficiency_attributes(volume_name, - dedup_enabled, - compression_enabled) + efficiency_policy = options.get('efficiency_policy', None) + self.update_volume_efficiency_attributes( + volume_name, dedup_enabled, compression_enabled, + efficiency_policy=efficiency_policy + ) if max_files is not None: self.set_volume_max_files(volume_name, max_files) @@ -2377,6 +2379,28 @@ class NetAppCmodeClient(client_base.NetAppBaseClient): } self.connection.send_request('sis-set-config-async', api_args) + @na_utils.trace + def apply_volume_efficiency_policy(self, volume_name, + efficiency_policy=None): + """Apply efficiency policy to FlexVol/FlexGroup volume.""" + if efficiency_policy: + api_args = { + 'path': f'/vol/{volume_name}', + 'policy-name': efficiency_policy + } + self.send_request('sis-set-config', api_args) + + @na_utils.trace + def apply_volume_efficiency_policy_async(self, volume_name, + efficiency_policy=None): + """Apply efficiency policy to FlexVol volume asynchronously.""" + if efficiency_policy: + api_args = { + 'path': f'/vol/{volume_name}', + 'policy-name': efficiency_policy + } + self.connection.send_request('sis-set-config-async', api_args) + @na_utils.trace def get_volume_efficiency_status(self, volume_name): """Get dedupe & compression status for a volume.""" @@ -2664,17 +2688,18 @@ class NetAppCmodeClient(client_base.NetAppBaseClient): not hide_snapdir).lower() self.send_request('volume-modify-iter', api_args) - + efficiency_policy = options.get('efficiency_policy', None) # Efficiency options must be handled separately - self.update_volume_efficiency_attributes(volume_name, - dedup_enabled, - compression_enabled, - is_flexgroup=is_flexgroup) + self.update_volume_efficiency_attributes( + volume_name, dedup_enabled, compression_enabled, + is_flexgroup=is_flexgroup, efficiency_policy=efficiency_policy + ) @na_utils.trace def update_volume_efficiency_attributes(self, volume_name, dedup_enabled, compression_enabled, - is_flexgroup=False): + is_flexgroup=False, + efficiency_policy=None): """Update dedupe & compression attributes to match desired values.""" efficiency_status = self.get_volume_efficiency_status(volume_name) @@ -2705,6 +2730,13 @@ class NetAppCmodeClient(client_base.NetAppBaseClient): else: self.disable_compression(volume_name) + if is_flexgroup: + self.apply_volume_efficiency_policy_async( + volume_name, efficiency_policy=efficiency_policy) + else: + self.apply_volume_efficiency_policy( + volume_name, efficiency_policy=efficiency_policy) + @na_utils.trace def volume_exists(self, volume_name): """Checks if volume exists.""" diff --git a/manila/share/drivers/netapp/dataontap/client/client_cmode_rest.py b/manila/share/drivers/netapp/dataontap/client/client_cmode_rest.py index f83b227ed0..7b5af49453 100644 --- a/manila/share/drivers/netapp/dataontap/client/client_cmode_rest.py +++ b/manila/share/drivers/netapp/dataontap/client/client_cmode_rest.py @@ -968,10 +968,11 @@ class NetAppRestClient(object): qos_policy_group=qos_policy_group, encrypt=encrypt, adaptive_qos_policy_group=adaptive_qos_policy_group, mount_point_name=mount_point_name, **options) - - self.update_volume_efficiency_attributes(volume_name, - dedup_enabled, - compression_enabled) + efficiency_policy = options.get('efficiency_policy', None) + self.update_volume_efficiency_attributes( + volume_name, dedup_enabled, compression_enabled, + efficiency_policy=efficiency_policy + ) if max_files is not None: self.set_volume_max_files(volume_name, max_files) @@ -1113,7 +1114,8 @@ class NetAppRestClient(object): @na_utils.trace def update_volume_efficiency_attributes(self, volume_name, dedup_enabled, compression_enabled, - is_flexgroup=None): + is_flexgroup=False, + efficiency_policy=None): """Update dedupe & compression attributes to match desired values.""" efficiency_status = self.get_volume_efficiency_status(volume_name) @@ -1130,6 +1132,9 @@ class NetAppRestClient(object): elif not compression_enabled and efficiency_status['compression']: self.disable_compression_async(volume_name) + self.apply_volume_efficiency_policy( + volume_name, efficiency_policy=efficiency_policy) + @na_utils.trace def enable_dedupe_async(self, volume_name): """Enable deduplication on FlexVol/FlexGroup volume asynchronously.""" @@ -1181,6 +1186,21 @@ class NetAppRestClient(object): # update volume efficiency self.send_request(f'/storage/volumes/{uuid}', 'patch', body=body) + @na_utils.trace + def apply_volume_efficiency_policy(self, volume_name, + efficiency_policy=None): + if efficiency_policy: + """Apply volume efficiency policy to FlexVol""" + volume = self._get_volume_by_args(vol_name=volume_name) + uuid = volume['uuid'] + + body = { + 'efficiency': {'policy': efficiency_policy} + } + + # update volume efficiency policy only if policy_name is provided + self.send_request(f'/storage/volumes/{uuid}', 'patch', body=body) + @na_utils.trace def set_volume_max_files(self, volume_name, max_files): """Set share file limit.""" @@ -2513,12 +2533,13 @@ class NetAppRestClient(object): self.send_request('/storage/volumes/' + volume['uuid'], 'patch', body=body) - + # Extract efficiency_policy from provisioning_options + efficiency_policy = options.get('efficiency_policy', None) # Efficiency options must be handled separately - self.update_volume_efficiency_attributes(volume_name, - dedup_enabled, - compression_enabled, - is_flexgroup=is_flexgroup) + self.update_volume_efficiency_attributes( + volume_name, dedup_enabled, compression_enabled, + is_flexgroup=is_flexgroup, efficiency_policy=efficiency_policy + ) @na_utils.trace def start_volume_move(self, volume_name, vserver, destination_aggregate, diff --git a/manila/share/drivers/netapp/dataontap/cluster_mode/lib_base.py b/manila/share/drivers/netapp/dataontap/cluster_mode/lib_base.py index 01b18eb286..14b7b48b86 100644 --- a/manila/share/drivers/netapp/dataontap/cluster_mode/lib_base.py +++ b/manila/share/drivers/netapp/dataontap/cluster_mode/lib_base.py @@ -118,6 +118,7 @@ class NetAppCmodeFileStorageLibrary(object): 'netapp:fpolicy_extensions_to_exclude': 'fpolicy_extensions_to_exclude', 'netapp:fpolicy_file_operations': 'fpolicy_file_operations', + 'netapp:efficiency_policy': 'efficiency_policy', } # Maps standard extra spec keys to legacy NetApp keys @@ -1137,6 +1138,7 @@ class NetAppCmodeFileStorageLibrary(object): 'provisioning options %(options)s', {'share': share_name, 'pool': pool_name, 'options': provisioning_options}) + if self._is_flexgroup_pool(pool_name): aggr_list = self._get_flexgroup_aggregate_list(pool_name) self._create_flexgroup_share( @@ -1195,9 +1197,11 @@ class NetAppCmodeFileStorageLibrary(object): timeout = self.configuration.netapp_flexgroup_volume_online_timeout self.wait_for_flexgroup_deployment(vserver_client, job_info['jobid'], timeout) + efficiency_policy = provisioning_options.get('efficiency_policy', None) vserver_client.update_volume_efficiency_attributes( - share_name, dedup_enabled, compression_enabled, is_flexgroup=True) + share_name, dedup_enabled, compression_enabled, is_flexgroup=True, + efficiency_policy=efficiency_policy) if max_files is not None: vserver_client.set_volume_max_files(share_name, max_files) diff --git a/manila/tests/share/drivers/netapp/dataontap/client/fakes.py b/manila/tests/share/drivers/netapp/dataontap/client/fakes.py index 1a3613f5c2..9d9bbecbbf 100644 --- a/manila/tests/share/drivers/netapp/dataontap/client/fakes.py +++ b/manila/tests/share/drivers/netapp/dataontap/client/fakes.py @@ -77,6 +77,7 @@ MAX_FILES = 5000 LANGUAGE = 'fake_language' SNAPSHOT_POLICY_NAME = 'fake_snapshot_policy' EXPORT_POLICY_NAME = 'fake_export_policy' +VOLUME_EFFICIENCY_POLICY_NAME = 'fake_volume_efficiency_policy' DELETED_EXPORT_POLICIES = { VSERVER_NAME: [ 'deleted_manila_fake_policy_1', diff --git a/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py b/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py index 5d1da06547..c33bc2bb87 100644 --- a/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py +++ b/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py @@ -3203,10 +3203,13 @@ class NetAppClientCmodeTestCase(test.TestCase): self.mock_object( self.client, '_get_create_volume_api_args', mock.Mock(return_value={})) + options = {'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME} self.client.create_volume( fake.SHARE_AGGREGATE_NAME, fake.SHARE_NAME, 100, - max_files=fake.MAX_FILES if set_max_files else None) + max_files=fake.MAX_FILES if set_max_files else None, + **options + ) volume_create_args = { 'containing-aggr-name': fake.SHARE_AGGREGATE_NAME, @@ -3219,8 +3222,12 @@ class NetAppClientCmodeTestCase(test.TestCase): None, None) self.client.send_request.assert_called_with('volume-create', volume_create_args) - (self.client.update_volume_efficiency_attributes. - assert_called_once_with(fake.SHARE_NAME, False, False)) + ( + self.client.update_volume_efficiency_attributes. + assert_called_once_with + (fake.SHARE_NAME, False, False, + efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME) + ) if set_max_files: self.client.set_volume_max_files.assert_called_once_with( fake.SHARE_NAME, fake.MAX_FILES) @@ -3587,6 +3594,50 @@ class NetAppClientCmodeTestCase(test.TestCase): self.client.connection.send_request.assert_called_once_with( 'sis-set-config-async', sis_set_config_args) + def test_apply_volume_efficiency_policy_with_policy(self): + self.mock_object(self.client, 'send_request') + self.client.apply_volume_efficiency_policy( + fake.SHARE_NAME, fake.VOLUME_EFFICIENCY_POLICY_NAME + ) + + volume_efficiency_config_args = { + 'path': '/vol/%s' % fake.SHARE_NAME, + 'policy-name': fake.VOLUME_EFFICIENCY_POLICY_NAME + } + + self.client.send_request.assert_called_once_with( + 'sis-set-config', volume_efficiency_config_args) + + def test_apply_volume_efficiency_policy_without_policy(self): + self.mock_object(self.client, 'send_request') + self.client.apply_volume_efficiency_policy( + fake.SHARE_NAME, None + ) + + self.client.send_request.assert_not_called() + + def test_apply_volume_efficiency_policy_async_with_policy(self): + self.mock_object(self.client.connection, 'send_request') + self.client.apply_volume_efficiency_policy_async( + fake.SHARE_NAME, fake.VOLUME_EFFICIENCY_POLICY_NAME + ) + + volume_efficiency_config_args = { + 'path': '/vol/%s' % fake.SHARE_NAME, + 'policy-name': fake.VOLUME_EFFICIENCY_POLICY_NAME + } + + self.client.connection.send_request.assert_called_once_with( + 'sis-set-config-async', volume_efficiency_config_args) + + def test_apply_volume_efficiency_policy_async_without_policy(self): + self.mock_object(self.client.connection, 'send_request') + self.client.apply_volume_efficiency_policy_async( + fake.SHARE_NAME + ) + + self.client.connection.send_request.assert_not_called() + def test_get_volume_efficiency_status(self): api_response = netapp_api.NaElement(fake.SIS_GET_ITER_RESPONSE) @@ -3727,7 +3778,9 @@ class NetAppClientCmodeTestCase(test.TestCase): self.client.send_request.assert_called_once_with( 'volume-modify-iter', volume_modify_iter_api_args) mock_update_volume_efficiency_attributes.assert_called_once_with( - fake.SHARE_NAME, False, False, is_flexgroup=is_flexgroup) + fake.SHARE_NAME, False, False, + is_flexgroup=is_flexgroup, efficiency_policy=None + ) @ddt.data((fake.QOS_POLICY_GROUP_NAME, None), (None, fake.ADAPTIVE_QOS_POLICY_GROUP_NAME)) @@ -3738,6 +3791,7 @@ class NetAppClientCmodeTestCase(test.TestCase): self.mock_object(self.client, 'send_request') mock_update_volume_efficiency_attributes = self.mock_object( self.client, 'update_volume_efficiency_attributes') + options = {'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME} self.client.modify_volume( fake.SHARE_AGGREGATE_NAME, @@ -3751,7 +3805,9 @@ class NetAppClientCmodeTestCase(test.TestCase): qos_policy_group=qos_group, adaptive_qos_policy_group=adaptive_qos_group, autosize_attributes=fake.VOLUME_AUTOSIZE_ATTRS, - hide_snapdir=True) + hide_snapdir=True, + **options + ) volume_modify_iter_api_args = { 'query': { @@ -3801,30 +3857,52 @@ class NetAppClientCmodeTestCase(test.TestCase): self.client.send_request.assert_called_once_with( 'volume-modify-iter', volume_modify_iter_api_args) mock_update_volume_efficiency_attributes.assert_called_once_with( - fake.SHARE_NAME, True, False, is_flexgroup=False) + fake.SHARE_NAME, True, False, + is_flexgroup=False, + efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME + ) @ddt.data( - {'existing': (True, True), 'desired': (True, True), 'fg': False}, - {'existing': (True, True), 'desired': (False, False), 'fg': False}, - {'existing': (True, True), 'desired': (True, False), 'fg': False}, - {'existing': (True, False), 'desired': (True, False), 'fg': False}, - {'existing': (True, False), 'desired': (False, False), 'fg': False}, - {'existing': (True, False), 'desired': (True, True), 'fg': False}, - {'existing': (False, False), 'desired': (False, False), 'fg': False}, - {'existing': (False, False), 'desired': (True, False), 'fg': False}, - {'existing': (False, False), 'desired': (True, True), 'fg': False}, - {'existing': (True, True), 'desired': (True, True), 'fg': True}, - {'existing': (True, True), 'desired': (False, False), 'fg': True}, - {'existing': (True, True), 'desired': (True, False), 'fg': True}, - {'existing': (True, False), 'desired': (True, False), 'fg': True}, - {'existing': (True, False), 'desired': (False, False), 'fg': True}, - {'existing': (True, False), 'desired': (True, True), 'fg': True}, - {'existing': (False, False), 'desired': (False, False), 'fg': True}, - {'existing': (False, False), 'desired': (True, False), 'fg': True}, - {'existing': (False, False), 'desired': (True, True), 'fg': True}, + {'existing': (True, True), 'desired': (True, True), 'fg': False, + 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}, + {'existing': (True, True), 'desired': (False, False), 'fg': False, + 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}, + {'existing': (True, True), 'desired': (True, False), 'fg': False, + 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}, + {'existing': (True, False), 'desired': (True, False), 'fg': False, + 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}, + {'existing': (True, False), 'desired': (False, False), 'fg': False, + 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}, + {'existing': (True, False), 'desired': (True, True), 'fg': False, + 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}, + {'existing': (False, False), 'desired': (False, False), 'fg': False, + 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}, + {'existing': (False, False), 'desired': (True, False), 'fg': False, + 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}, + {'existing': (False, False), 'desired': (True, True), 'fg': False, + 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}, + {'existing': (True, True), 'desired': (True, True), 'fg': True, + 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}, + {'existing': (True, True), 'desired': (False, False), 'fg': True, + 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}, + {'existing': (True, True), 'desired': (True, False), 'fg': True, + 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}, + {'existing': (True, False), 'desired': (True, False), 'fg': True, + 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}, + {'existing': (True, False), 'desired': (False, False), 'fg': True, + 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}, + {'existing': (True, False), 'desired': (True, True), 'fg': True, + 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}, + {'existing': (False, False), 'desired': (False, False), 'fg': True, + 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}, + {'existing': (False, False), 'desired': (True, False), 'fg': True, + 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}, + {'existing': (False, False), 'desired': (True, True), 'fg': True, + 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}, ) @ddt.unpack - def test_update_volume_efficiency_attributes(self, existing, desired, fg): + def test_update_volume_efficiency_attributes(self, existing, desired, fg, + efficiency_policy): existing_dedupe = existing[0] existing_compression = existing[1] @@ -3850,10 +3928,17 @@ class NetAppClientCmodeTestCase(test.TestCase): mock_disable_dedup = self.mock_object(self.client, 'disable_dedup') mock_disable_dedup_async = self.mock_object(self.client, 'disable_dedupe_async') + mock_apply_volume_efficiency_policy = ( + self.mock_object(self.client, 'apply_volume_efficiency_policy')) + mock_apply_volume_efficiency_policy_async = ( + self.mock_object(self.client, + 'apply_volume_efficiency_policy_async' + ) + ) self.client.update_volume_efficiency_attributes( fake.SHARE_NAME, desired_dedupe, desired_compression, - is_flexgroup=fg) + is_flexgroup=fg, efficiency_policy=efficiency_policy) if existing_dedupe == desired_dedupe: if fg: @@ -3899,6 +3984,11 @@ class NetAppClientCmodeTestCase(test.TestCase): self.assertTrue(mock_enable_compression.called) self.assertFalse(mock_disable_compression.called) + if fg: + self.assertTrue(mock_apply_volume_efficiency_policy_async.called) + else: + self.assertTrue(mock_apply_volume_efficiency_policy.called) + def test_set_volume_size(self): api_response = netapp_api.NaElement(fake.VOLUME_MODIFY_ITER_RESPONSE) diff --git a/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode_rest.py b/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode_rest.py index b37a6cb538..360d9caea4 100644 --- a/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode_rest.py +++ b/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode_rest.py @@ -1036,17 +1036,22 @@ class NetAppRestCmodeClientTestCase(test.TestCase): mock_update = self.mock_object( self.client, 'update_volume_efficiency_attributes') mock_max_files = self.mock_object(self.client, 'set_volume_max_files') + options = {'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME} self.client.create_volume(fake.SHARE_AGGREGATE_NAME, fake.VOLUME_NAMES[0], fake.SHARE_SIZE, - max_files=1) + max_files=1, **options) mock_create_volume_async.assert_called_once_with( [fake.SHARE_AGGREGATE_NAME], fake.VOLUME_NAMES[0], fake.SHARE_SIZE, is_flexgroup=False, thin_provisioned=False, snapshot_policy=None, language=None, max_files=1, snapshot_reserve=None, volume_type='rw', qos_policy_group=None, encrypt=False, - adaptive_qos_policy_group=None, mount_point_name=None) - mock_update.assert_called_once_with(fake.VOLUME_NAMES[0], False, False) + adaptive_qos_policy_group=None, mount_point_name=None, + efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME + ) + mock_update.assert_called_once_with( + fake.VOLUME_NAMES[0], False, False, + efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME) mock_max_files.assert_called_once_with(fake.VOLUME_NAMES[0], 1) def test_create_volume_async(self): @@ -1187,6 +1192,46 @@ class NetAppRestCmodeClientTestCase(test.TestCase): self.client._get_volume_by_args.assert_called_once_with( vol_name=fake.VOLUME_NAMES[0]) + def test_apply_volume_efficiency_policy(self): + volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST + uuid = volume["uuid"] + return_value = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST + + self.mock_object(self.client, '_get_volume_by_args', + mock.Mock(return_value=volume)) + self.mock_object(self.client, 'send_request', + mock.Mock(return_value=return_value)) + + body = { + 'efficiency': {'policy': fake.VOLUME_EFFICIENCY_POLICY_NAME} + } + + self.client.apply_volume_efficiency_policy( + fake.VOLUME_NAMES[0], + efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME + ) + + self.client.send_request.assert_called_once_with( + f'/storage/volumes/{uuid}', 'patch', body=body) + self.client._get_volume_by_args.assert_called_once_with( + vol_name=fake.VOLUME_NAMES[0]) + + def test_apply_volume_efficiency_none_policy(self): + volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST + return_value = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST + + self.mock_object(self.client, '_get_volume_by_args', + mock.Mock(return_value=volume)) + self.mock_object(self.client, 'send_request', + mock.Mock(return_value=return_value)) + + self.client.apply_volume_efficiency_policy( + fake.VOLUME_NAMES[0], + efficiency_policy=None + ) + + self.client._get_volume_by_args.assert_not_called() + def test_set_volume_max_files(self): volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST uuid = volume["uuid"] @@ -2313,7 +2358,9 @@ class NetAppRestCmodeClientTestCase(test.TestCase): self.client.send_request.assert_called_once_with( '/storage/volumes/' + volume['uuid'], 'patch', body=body) mock_update_volume_efficiency_attributes.assert_called_once_with( - fake.SHARE_NAME, False, False, is_flexgroup=is_flexgroup) + fake.SHARE_NAME, False, False, + is_flexgroup=is_flexgroup, efficiency_policy=None + ) @ddt.data((fake.QOS_POLICY_GROUP_NAME, None), (None, fake.ADAPTIVE_QOS_POLICY_GROUP_NAME)) @@ -2328,6 +2375,7 @@ class NetAppRestCmodeClientTestCase(test.TestCase): volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST self.mock_object(self.client, '_get_volume_by_args', mock.Mock(return_value=volume)) + options = {'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME} self.client.modify_volume( fake.SHARE_AGGREGATE_NAME, @@ -2341,7 +2389,9 @@ class NetAppRestCmodeClientTestCase(test.TestCase): qos_policy_group=qos_group, adaptive_qos_policy_group=adaptive_qos_group, autosize_attributes=fake.VOLUME_AUTOSIZE_ATTRS, - hide_snapdir=True) + hide_snapdir=True, + **options + ) qos_policy_name = qos_group or adaptive_qos_group body = { @@ -2363,7 +2413,10 @@ class NetAppRestCmodeClientTestCase(test.TestCase): self.client.send_request.assert_called_once_with( '/storage/volumes/' + volume['uuid'], 'patch', body=body) mock_update_volume_efficiency_attributes.assert_called_once_with( - fake.SHARE_NAME, True, False, is_flexgroup=False) + fake.SHARE_NAME, True, False, + is_flexgroup=False, + efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME + ) def test__parse_timestamp(self): test_time_str = '2022-11-25T14:41:20+00:00' @@ -2778,16 +2831,29 @@ class NetAppRestCmodeClientTestCase(test.TestCase): dis_dedupe = self.mock_object(self.client, 'disable_dedupe_async') en_comp = self.mock_object(self.client, 'enable_compression_async') dis_comp = self.mock_object(self.client, 'disable_compression_async') + apply_efficiency_policy = self.mock_object( + self.client, 'apply_volume_efficiency_policy' + ) - self.client.update_volume_efficiency_attributes(fake.VOLUME_NAMES[0], - status, status) + self.client.update_volume_efficiency_attributes( + fake.VOLUME_NAMES[0], + status, status, + efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME) if status: en_dedupe.assert_called_once_with(fake.VOLUME_NAMES[0]) en_comp.assert_called_once_with(fake.VOLUME_NAMES[0]) + apply_efficiency_policy.assert_called_once_with( + fake.VOLUME_NAMES[0], + efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME + ) else: dis_dedupe.assert_called_once_with(fake.VOLUME_NAMES[0]) dis_comp.assert_called_once_with(fake.VOLUME_NAMES[0]) + apply_efficiency_policy.assert_called_once_with( + fake.VOLUME_NAMES[0], + efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME + ) def test_trigger_volume_move_cutover(self): query = { diff --git a/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_base.py b/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_base.py index 67d11cbce1..3711065506 100644 --- a/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_base.py +++ b/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_base.py @@ -1624,21 +1624,23 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): mock_wait_for_flexgroup_deployment = self.mock_object( self.library, 'wait_for_flexgroup_deployment') aggr_list = [fake.AGGREGATE] - + options = {'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME} self.library._create_flexgroup_share(vserver_client, aggr_list, fake.SHARE_NAME, 100, 10, - max_files=max_files) + max_files=max_files, **options) start_timeout = (self.library.configuration. netapp_flexgroup_aggregate_not_busy_timeout) mock_wait_for_start.assert_called_once_with( start_timeout, vserver_client, aggr_list, fake.SHARE_NAME, 100, - 10, None) + 10, None, efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME) mock_wait_for_flexgroup_deployment.assert_called_once_with( vserver_client, fake.JOB_ID, 2) - (vserver_client.update_volume_efficiency_attributes. - assert_called_once_with(fake.SHARE_NAME, False, False, - is_flexgroup=True)) + vserver_client.update_volume_efficiency_attributes.assert_called_once_with( # noqa + fake.SHARE_NAME, False, False, + is_flexgroup=True, + efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME + ) if max_files: vserver_client.set_volume_max_files.assert_called_once_with( fake.SHARE_NAME, max_files) @@ -1876,6 +1878,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): 'fpolicy_extensions_to_exclude': None, 'fpolicy_extensions_to_include': None, 'fpolicy_file_operations': None, + 'efficiency_policy': None, } self.assertEqual(expected, result) diff --git a/manila/tests/share/drivers/netapp/dataontap/fakes.py b/manila/tests/share/drivers/netapp/dataontap/fakes.py index ee96899518..98ae50cd90 100644 --- a/manila/tests/share/drivers/netapp/dataontap/fakes.py +++ b/manila/tests/share/drivers/netapp/dataontap/fakes.py @@ -115,6 +115,7 @@ FPOLICY_EXT_TO_EXCLUDE = 'jpg,mp3' FPOLICY_EXT_TO_EXCLUDE_LIST = ['jpg', 'mp3'] BACKUP_TYPE = "fake_backup_type" MOUNT_POINT_NAME = 'fake_mp' +VOLUME_EFFICIENCY_POLICY_NAME = 'fake_volume_efficiency_policy' JOB_ID = '123' JOB_STATE = 'success' @@ -408,6 +409,7 @@ PROVISIONING_OPTIONS_STRING = { 'fpolicy_extensions_to_exclude': None, 'fpolicy_extensions_to_include': None, 'fpolicy_file_operations': None, + 'efficiency_policy': None } PROVISIONING_OPTIONS_STRING_MISSING_SPECS = { @@ -418,6 +420,7 @@ PROVISIONING_OPTIONS_STRING_MISSING_SPECS = { 'fpolicy_extensions_to_exclude': None, 'fpolicy_extensions_to_include': None, 'fpolicy_file_operations': None, + 'efficiency_policy': None, } PROVISIONING_OPTIONS_STRING_DEFAULT = { @@ -428,6 +431,7 @@ PROVISIONING_OPTIONS_STRING_DEFAULT = { 'fpolicy_extensions_to_exclude': None, 'fpolicy_extensions_to_include': None, 'fpolicy_file_operations': None, + 'efficiency_policy': None, } SHORT_BOOLEAN_EXTRA_SPEC = { @@ -439,6 +443,7 @@ STRING_EXTRA_SPEC = { 'netapp:language': 'en-US', 'netapp:max_files': 5000, 'netapp:adaptive_qos_policy_group': None, + 'netapp:efficiency_policy': None, } SHORT_STRING_EXTRA_SPEC = { diff --git a/releasenotes/notes/manila-netapp-storage-efficiency-policy-5fa0b2b15901bf93.yaml b/releasenotes/notes/manila-netapp-storage-efficiency-policy-5fa0b2b15901bf93.yaml new file mode 100644 index 0000000000..e32a2f8389 --- /dev/null +++ b/releasenotes/notes/manila-netapp-storage-efficiency-policy-5fa0b2b15901bf93.yaml @@ -0,0 +1,10 @@ +features: + - | + It is now possible to specify pre-created NetApp efficiency + policies through the use of the `netapp:efficiency_policy` share type + extra spec. + In the case of DHSS=True, the share server is not available upfront for + efficiency policy creation. Users can retype to apply the policy, or if the + share-network is constant (i.e., one share service is created for one share + network), they can create an efficiency policy for the share server and + apply it to DHSS=True shares. \ No newline at end of file