[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
This commit is contained in:
jayaanand borra 2024-07-29 02:44:22 -04:00
parent d773353502
commit 43538613ee
9 changed files with 292 additions and 60 deletions

View File

@ -2238,9 +2238,11 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
self.send_request('volume-create', api_args) self.send_request('volume-create', api_args)
self.update_volume_efficiency_attributes(volume_name, efficiency_policy = options.get('efficiency_policy', None)
dedup_enabled, self.update_volume_efficiency_attributes(
compression_enabled) volume_name, dedup_enabled, compression_enabled,
efficiency_policy=efficiency_policy
)
if max_files is not None: if max_files is not None:
self.set_volume_max_files(volume_name, max_files) 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) 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 @na_utils.trace
def get_volume_efficiency_status(self, volume_name): def get_volume_efficiency_status(self, volume_name):
"""Get dedupe & compression status for a volume.""" """Get dedupe & compression status for a volume."""
@ -2664,17 +2688,18 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
not hide_snapdir).lower() not hide_snapdir).lower()
self.send_request('volume-modify-iter', api_args) self.send_request('volume-modify-iter', api_args)
efficiency_policy = options.get('efficiency_policy', None)
# Efficiency options must be handled separately # Efficiency options must be handled separately
self.update_volume_efficiency_attributes(volume_name, self.update_volume_efficiency_attributes(
dedup_enabled, volume_name, dedup_enabled, compression_enabled,
compression_enabled, is_flexgroup=is_flexgroup, efficiency_policy=efficiency_policy
is_flexgroup=is_flexgroup) )
@na_utils.trace @na_utils.trace
def update_volume_efficiency_attributes(self, volume_name, dedup_enabled, def update_volume_efficiency_attributes(self, volume_name, dedup_enabled,
compression_enabled, compression_enabled,
is_flexgroup=False): is_flexgroup=False,
efficiency_policy=None):
"""Update dedupe & compression attributes to match desired values.""" """Update dedupe & compression attributes to match desired values."""
efficiency_status = self.get_volume_efficiency_status(volume_name) efficiency_status = self.get_volume_efficiency_status(volume_name)
@ -2705,6 +2730,13 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
else: else:
self.disable_compression(volume_name) 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 @na_utils.trace
def volume_exists(self, volume_name): def volume_exists(self, volume_name):
"""Checks if volume exists.""" """Checks if volume exists."""

View File

@ -968,10 +968,11 @@ class NetAppRestClient(object):
qos_policy_group=qos_policy_group, encrypt=encrypt, qos_policy_group=qos_policy_group, encrypt=encrypt,
adaptive_qos_policy_group=adaptive_qos_policy_group, adaptive_qos_policy_group=adaptive_qos_policy_group,
mount_point_name=mount_point_name, **options) mount_point_name=mount_point_name, **options)
efficiency_policy = options.get('efficiency_policy', None)
self.update_volume_efficiency_attributes(volume_name, self.update_volume_efficiency_attributes(
dedup_enabled, volume_name, dedup_enabled, compression_enabled,
compression_enabled) efficiency_policy=efficiency_policy
)
if max_files is not None: if max_files is not None:
self.set_volume_max_files(volume_name, max_files) self.set_volume_max_files(volume_name, max_files)
@ -1113,7 +1114,8 @@ class NetAppRestClient(object):
@na_utils.trace @na_utils.trace
def update_volume_efficiency_attributes(self, volume_name, dedup_enabled, def update_volume_efficiency_attributes(self, volume_name, dedup_enabled,
compression_enabled, compression_enabled,
is_flexgroup=None): is_flexgroup=False,
efficiency_policy=None):
"""Update dedupe & compression attributes to match desired values.""" """Update dedupe & compression attributes to match desired values."""
efficiency_status = self.get_volume_efficiency_status(volume_name) efficiency_status = self.get_volume_efficiency_status(volume_name)
@ -1130,6 +1132,9 @@ class NetAppRestClient(object):
elif not compression_enabled and efficiency_status['compression']: elif not compression_enabled and efficiency_status['compression']:
self.disable_compression_async(volume_name) self.disable_compression_async(volume_name)
self.apply_volume_efficiency_policy(
volume_name, efficiency_policy=efficiency_policy)
@na_utils.trace @na_utils.trace
def enable_dedupe_async(self, volume_name): def enable_dedupe_async(self, volume_name):
"""Enable deduplication on FlexVol/FlexGroup volume asynchronously.""" """Enable deduplication on FlexVol/FlexGroup volume asynchronously."""
@ -1181,6 +1186,21 @@ class NetAppRestClient(object):
# update volume efficiency # update volume efficiency
self.send_request(f'/storage/volumes/{uuid}', 'patch', body=body) 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 @na_utils.trace
def set_volume_max_files(self, volume_name, max_files): def set_volume_max_files(self, volume_name, max_files):
"""Set share file limit.""" """Set share file limit."""
@ -2513,12 +2533,13 @@ class NetAppRestClient(object):
self.send_request('/storage/volumes/' + volume['uuid'], self.send_request('/storage/volumes/' + volume['uuid'],
'patch', body=body) 'patch', body=body)
# Extract efficiency_policy from provisioning_options
efficiency_policy = options.get('efficiency_policy', None)
# Efficiency options must be handled separately # Efficiency options must be handled separately
self.update_volume_efficiency_attributes(volume_name, self.update_volume_efficiency_attributes(
dedup_enabled, volume_name, dedup_enabled, compression_enabled,
compression_enabled, is_flexgroup=is_flexgroup, efficiency_policy=efficiency_policy
is_flexgroup=is_flexgroup) )
@na_utils.trace @na_utils.trace
def start_volume_move(self, volume_name, vserver, destination_aggregate, def start_volume_move(self, volume_name, vserver, destination_aggregate,

View File

@ -118,6 +118,7 @@ class NetAppCmodeFileStorageLibrary(object):
'netapp:fpolicy_extensions_to_exclude': 'netapp:fpolicy_extensions_to_exclude':
'fpolicy_extensions_to_exclude', 'fpolicy_extensions_to_exclude',
'netapp:fpolicy_file_operations': 'fpolicy_file_operations', 'netapp:fpolicy_file_operations': 'fpolicy_file_operations',
'netapp:efficiency_policy': 'efficiency_policy',
} }
# Maps standard extra spec keys to legacy NetApp keys # Maps standard extra spec keys to legacy NetApp keys
@ -1137,6 +1138,7 @@ class NetAppCmodeFileStorageLibrary(object):
'provisioning options %(options)s', 'provisioning options %(options)s',
{'share': share_name, 'pool': pool_name, {'share': share_name, 'pool': pool_name,
'options': provisioning_options}) 'options': provisioning_options})
if self._is_flexgroup_pool(pool_name): if self._is_flexgroup_pool(pool_name):
aggr_list = self._get_flexgroup_aggregate_list(pool_name) aggr_list = self._get_flexgroup_aggregate_list(pool_name)
self._create_flexgroup_share( self._create_flexgroup_share(
@ -1195,9 +1197,11 @@ class NetAppCmodeFileStorageLibrary(object):
timeout = self.configuration.netapp_flexgroup_volume_online_timeout timeout = self.configuration.netapp_flexgroup_volume_online_timeout
self.wait_for_flexgroup_deployment(vserver_client, job_info['jobid'], self.wait_for_flexgroup_deployment(vserver_client, job_info['jobid'],
timeout) timeout)
efficiency_policy = provisioning_options.get('efficiency_policy', None)
vserver_client.update_volume_efficiency_attributes( 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: if max_files is not None:
vserver_client.set_volume_max_files(share_name, max_files) vserver_client.set_volume_max_files(share_name, max_files)

View File

@ -77,6 +77,7 @@ MAX_FILES = 5000
LANGUAGE = 'fake_language' LANGUAGE = 'fake_language'
SNAPSHOT_POLICY_NAME = 'fake_snapshot_policy' SNAPSHOT_POLICY_NAME = 'fake_snapshot_policy'
EXPORT_POLICY_NAME = 'fake_export_policy' EXPORT_POLICY_NAME = 'fake_export_policy'
VOLUME_EFFICIENCY_POLICY_NAME = 'fake_volume_efficiency_policy'
DELETED_EXPORT_POLICIES = { DELETED_EXPORT_POLICIES = {
VSERVER_NAME: [ VSERVER_NAME: [
'deleted_manila_fake_policy_1', 'deleted_manila_fake_policy_1',

View File

@ -3203,10 +3203,13 @@ class NetAppClientCmodeTestCase(test.TestCase):
self.mock_object( self.mock_object(
self.client, '_get_create_volume_api_args', self.client, '_get_create_volume_api_args',
mock.Mock(return_value={})) mock.Mock(return_value={}))
options = {'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}
self.client.create_volume( self.client.create_volume(
fake.SHARE_AGGREGATE_NAME, fake.SHARE_NAME, 100, 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 = { volume_create_args = {
'containing-aggr-name': fake.SHARE_AGGREGATE_NAME, 'containing-aggr-name': fake.SHARE_AGGREGATE_NAME,
@ -3219,8 +3222,12 @@ class NetAppClientCmodeTestCase(test.TestCase):
None, None) None, None)
self.client.send_request.assert_called_with('volume-create', self.client.send_request.assert_called_with('volume-create',
volume_create_args) 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: if set_max_files:
self.client.set_volume_max_files.assert_called_once_with( self.client.set_volume_max_files.assert_called_once_with(
fake.SHARE_NAME, fake.MAX_FILES) fake.SHARE_NAME, fake.MAX_FILES)
@ -3587,6 +3594,50 @@ class NetAppClientCmodeTestCase(test.TestCase):
self.client.connection.send_request.assert_called_once_with( self.client.connection.send_request.assert_called_once_with(
'sis-set-config-async', sis_set_config_args) '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): def test_get_volume_efficiency_status(self):
api_response = netapp_api.NaElement(fake.SIS_GET_ITER_RESPONSE) 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( self.client.send_request.assert_called_once_with(
'volume-modify-iter', volume_modify_iter_api_args) 'volume-modify-iter', volume_modify_iter_api_args)
mock_update_volume_efficiency_attributes.assert_called_once_with( 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), @ddt.data((fake.QOS_POLICY_GROUP_NAME, None),
(None, fake.ADAPTIVE_QOS_POLICY_GROUP_NAME)) (None, fake.ADAPTIVE_QOS_POLICY_GROUP_NAME))
@ -3738,6 +3791,7 @@ class NetAppClientCmodeTestCase(test.TestCase):
self.mock_object(self.client, 'send_request') self.mock_object(self.client, 'send_request')
mock_update_volume_efficiency_attributes = self.mock_object( mock_update_volume_efficiency_attributes = self.mock_object(
self.client, 'update_volume_efficiency_attributes') self.client, 'update_volume_efficiency_attributes')
options = {'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}
self.client.modify_volume( self.client.modify_volume(
fake.SHARE_AGGREGATE_NAME, fake.SHARE_AGGREGATE_NAME,
@ -3751,7 +3805,9 @@ class NetAppClientCmodeTestCase(test.TestCase):
qos_policy_group=qos_group, qos_policy_group=qos_group,
adaptive_qos_policy_group=adaptive_qos_group, adaptive_qos_policy_group=adaptive_qos_group,
autosize_attributes=fake.VOLUME_AUTOSIZE_ATTRS, autosize_attributes=fake.VOLUME_AUTOSIZE_ATTRS,
hide_snapdir=True) hide_snapdir=True,
**options
)
volume_modify_iter_api_args = { volume_modify_iter_api_args = {
'query': { 'query': {
@ -3801,30 +3857,52 @@ class NetAppClientCmodeTestCase(test.TestCase):
self.client.send_request.assert_called_once_with( self.client.send_request.assert_called_once_with(
'volume-modify-iter', volume_modify_iter_api_args) 'volume-modify-iter', volume_modify_iter_api_args)
mock_update_volume_efficiency_attributes.assert_called_once_with( 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( @ddt.data(
{'existing': (True, True), 'desired': (True, True), 'fg': False}, {'existing': (True, True), 'desired': (True, True), 'fg': False,
{'existing': (True, True), 'desired': (False, False), 'fg': False}, 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
{'existing': (True, True), 'desired': (True, False), 'fg': False}, {'existing': (True, True), 'desired': (False, False), 'fg': False,
{'existing': (True, False), 'desired': (True, False), 'fg': False}, 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
{'existing': (True, False), 'desired': (False, False), 'fg': False}, {'existing': (True, True), 'desired': (True, False), 'fg': False,
{'existing': (True, False), 'desired': (True, True), 'fg': False}, 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
{'existing': (False, False), 'desired': (False, False), 'fg': False}, {'existing': (True, False), 'desired': (True, False), 'fg': False,
{'existing': (False, False), 'desired': (True, False), 'fg': False}, 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
{'existing': (False, False), 'desired': (True, True), 'fg': False}, {'existing': (True, False), 'desired': (False, False), 'fg': False,
{'existing': (True, True), 'desired': (True, True), 'fg': True}, 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
{'existing': (True, True), 'desired': (False, False), 'fg': True}, {'existing': (True, False), 'desired': (True, True), 'fg': False,
{'existing': (True, True), 'desired': (True, False), 'fg': True}, 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
{'existing': (True, False), 'desired': (True, False), 'fg': True}, {'existing': (False, False), 'desired': (False, False), 'fg': False,
{'existing': (True, False), 'desired': (False, False), 'fg': True}, 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
{'existing': (True, False), 'desired': (True, True), 'fg': True}, {'existing': (False, False), 'desired': (True, False), 'fg': False,
{'existing': (False, False), 'desired': (False, False), 'fg': True}, 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
{'existing': (False, False), 'desired': (True, False), 'fg': True}, {'existing': (False, False), 'desired': (True, True), 'fg': False,
{'existing': (False, False), 'desired': (True, True), 'fg': True}, '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 @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_dedupe = existing[0]
existing_compression = existing[1] 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 = self.mock_object(self.client, 'disable_dedup')
mock_disable_dedup_async = self.mock_object(self.client, mock_disable_dedup_async = self.mock_object(self.client,
'disable_dedupe_async') '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( self.client.update_volume_efficiency_attributes(
fake.SHARE_NAME, desired_dedupe, desired_compression, fake.SHARE_NAME, desired_dedupe, desired_compression,
is_flexgroup=fg) is_flexgroup=fg, efficiency_policy=efficiency_policy)
if existing_dedupe == desired_dedupe: if existing_dedupe == desired_dedupe:
if fg: if fg:
@ -3899,6 +3984,11 @@ class NetAppClientCmodeTestCase(test.TestCase):
self.assertTrue(mock_enable_compression.called) self.assertTrue(mock_enable_compression.called)
self.assertFalse(mock_disable_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): def test_set_volume_size(self):
api_response = netapp_api.NaElement(fake.VOLUME_MODIFY_ITER_RESPONSE) api_response = netapp_api.NaElement(fake.VOLUME_MODIFY_ITER_RESPONSE)

View File

@ -1036,17 +1036,22 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
mock_update = self.mock_object( mock_update = self.mock_object(
self.client, 'update_volume_efficiency_attributes') self.client, 'update_volume_efficiency_attributes')
mock_max_files = self.mock_object(self.client, 'set_volume_max_files') 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, self.client.create_volume(fake.SHARE_AGGREGATE_NAME,
fake.VOLUME_NAMES[0], fake.SHARE_SIZE, fake.VOLUME_NAMES[0], fake.SHARE_SIZE,
max_files=1) max_files=1, **options)
mock_create_volume_async.assert_called_once_with( mock_create_volume_async.assert_called_once_with(
[fake.SHARE_AGGREGATE_NAME], fake.VOLUME_NAMES[0], fake.SHARE_SIZE, [fake.SHARE_AGGREGATE_NAME], fake.VOLUME_NAMES[0], fake.SHARE_SIZE,
is_flexgroup=False, thin_provisioned=False, snapshot_policy=None, is_flexgroup=False, thin_provisioned=False, snapshot_policy=None,
language=None, max_files=1, snapshot_reserve=None, language=None, max_files=1, snapshot_reserve=None,
volume_type='rw', qos_policy_group=None, encrypt=False, volume_type='rw', qos_policy_group=None, encrypt=False,
adaptive_qos_policy_group=None, mount_point_name=None) adaptive_qos_policy_group=None, mount_point_name=None,
mock_update.assert_called_once_with(fake.VOLUME_NAMES[0], False, False) 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) mock_max_files.assert_called_once_with(fake.VOLUME_NAMES[0], 1)
def test_create_volume_async(self): def test_create_volume_async(self):
@ -1187,6 +1192,46 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
self.client._get_volume_by_args.assert_called_once_with( self.client._get_volume_by_args.assert_called_once_with(
vol_name=fake.VOLUME_NAMES[0]) 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): def test_set_volume_max_files(self):
volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
uuid = volume["uuid"] uuid = volume["uuid"]
@ -2313,7 +2358,9 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
self.client.send_request.assert_called_once_with( self.client.send_request.assert_called_once_with(
'/storage/volumes/' + volume['uuid'], 'patch', body=body) '/storage/volumes/' + volume['uuid'], 'patch', body=body)
mock_update_volume_efficiency_attributes.assert_called_once_with( 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), @ddt.data((fake.QOS_POLICY_GROUP_NAME, None),
(None, fake.ADAPTIVE_QOS_POLICY_GROUP_NAME)) (None, fake.ADAPTIVE_QOS_POLICY_GROUP_NAME))
@ -2328,6 +2375,7 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
self.mock_object(self.client, '_get_volume_by_args', self.mock_object(self.client, '_get_volume_by_args',
mock.Mock(return_value=volume)) mock.Mock(return_value=volume))
options = {'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}
self.client.modify_volume( self.client.modify_volume(
fake.SHARE_AGGREGATE_NAME, fake.SHARE_AGGREGATE_NAME,
@ -2341,7 +2389,9 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
qos_policy_group=qos_group, qos_policy_group=qos_group,
adaptive_qos_policy_group=adaptive_qos_group, adaptive_qos_policy_group=adaptive_qos_group,
autosize_attributes=fake.VOLUME_AUTOSIZE_ATTRS, autosize_attributes=fake.VOLUME_AUTOSIZE_ATTRS,
hide_snapdir=True) hide_snapdir=True,
**options
)
qos_policy_name = qos_group or adaptive_qos_group qos_policy_name = qos_group or adaptive_qos_group
body = { body = {
@ -2363,7 +2413,10 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
self.client.send_request.assert_called_once_with( self.client.send_request.assert_called_once_with(
'/storage/volumes/' + volume['uuid'], 'patch', body=body) '/storage/volumes/' + volume['uuid'], 'patch', body=body)
mock_update_volume_efficiency_attributes.assert_called_once_with( 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): def test__parse_timestamp(self):
test_time_str = '2022-11-25T14:41:20+00:00' 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') dis_dedupe = self.mock_object(self.client, 'disable_dedupe_async')
en_comp = self.mock_object(self.client, 'enable_compression_async') en_comp = self.mock_object(self.client, 'enable_compression_async')
dis_comp = self.mock_object(self.client, 'disable_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], self.client.update_volume_efficiency_attributes(
status, status) fake.VOLUME_NAMES[0],
status, status,
efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME)
if status: if status:
en_dedupe.assert_called_once_with(fake.VOLUME_NAMES[0]) en_dedupe.assert_called_once_with(fake.VOLUME_NAMES[0])
en_comp.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: else:
dis_dedupe.assert_called_once_with(fake.VOLUME_NAMES[0]) dis_dedupe.assert_called_once_with(fake.VOLUME_NAMES[0])
dis_comp.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): def test_trigger_volume_move_cutover(self):
query = { query = {

View File

@ -1624,21 +1624,23 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
mock_wait_for_flexgroup_deployment = self.mock_object( mock_wait_for_flexgroup_deployment = self.mock_object(
self.library, 'wait_for_flexgroup_deployment') self.library, 'wait_for_flexgroup_deployment')
aggr_list = [fake.AGGREGATE] aggr_list = [fake.AGGREGATE]
options = {'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}
self.library._create_flexgroup_share(vserver_client, aggr_list, self.library._create_flexgroup_share(vserver_client, aggr_list,
fake.SHARE_NAME, 100, 10, fake.SHARE_NAME, 100, 10,
max_files=max_files) max_files=max_files, **options)
start_timeout = (self.library.configuration. start_timeout = (self.library.configuration.
netapp_flexgroup_aggregate_not_busy_timeout) netapp_flexgroup_aggregate_not_busy_timeout)
mock_wait_for_start.assert_called_once_with( mock_wait_for_start.assert_called_once_with(
start_timeout, vserver_client, aggr_list, fake.SHARE_NAME, 100, 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( mock_wait_for_flexgroup_deployment.assert_called_once_with(
vserver_client, fake.JOB_ID, 2) vserver_client, fake.JOB_ID, 2)
(vserver_client.update_volume_efficiency_attributes. vserver_client.update_volume_efficiency_attributes.assert_called_once_with( # noqa
assert_called_once_with(fake.SHARE_NAME, False, False, fake.SHARE_NAME, False, False,
is_flexgroup=True)) is_flexgroup=True,
efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME
)
if max_files: if max_files:
vserver_client.set_volume_max_files.assert_called_once_with( vserver_client.set_volume_max_files.assert_called_once_with(
fake.SHARE_NAME, max_files) fake.SHARE_NAME, max_files)
@ -1876,6 +1878,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
'fpolicy_extensions_to_exclude': None, 'fpolicy_extensions_to_exclude': None,
'fpolicy_extensions_to_include': None, 'fpolicy_extensions_to_include': None,
'fpolicy_file_operations': None, 'fpolicy_file_operations': None,
'efficiency_policy': None,
} }
self.assertEqual(expected, result) self.assertEqual(expected, result)

View File

@ -115,6 +115,7 @@ FPOLICY_EXT_TO_EXCLUDE = 'jpg,mp3'
FPOLICY_EXT_TO_EXCLUDE_LIST = ['jpg', 'mp3'] FPOLICY_EXT_TO_EXCLUDE_LIST = ['jpg', 'mp3']
BACKUP_TYPE = "fake_backup_type" BACKUP_TYPE = "fake_backup_type"
MOUNT_POINT_NAME = 'fake_mp' MOUNT_POINT_NAME = 'fake_mp'
VOLUME_EFFICIENCY_POLICY_NAME = 'fake_volume_efficiency_policy'
JOB_ID = '123' JOB_ID = '123'
JOB_STATE = 'success' JOB_STATE = 'success'
@ -408,6 +409,7 @@ PROVISIONING_OPTIONS_STRING = {
'fpolicy_extensions_to_exclude': None, 'fpolicy_extensions_to_exclude': None,
'fpolicy_extensions_to_include': None, 'fpolicy_extensions_to_include': None,
'fpolicy_file_operations': None, 'fpolicy_file_operations': None,
'efficiency_policy': None
} }
PROVISIONING_OPTIONS_STRING_MISSING_SPECS = { PROVISIONING_OPTIONS_STRING_MISSING_SPECS = {
@ -418,6 +420,7 @@ PROVISIONING_OPTIONS_STRING_MISSING_SPECS = {
'fpolicy_extensions_to_exclude': None, 'fpolicy_extensions_to_exclude': None,
'fpolicy_extensions_to_include': None, 'fpolicy_extensions_to_include': None,
'fpolicy_file_operations': None, 'fpolicy_file_operations': None,
'efficiency_policy': None,
} }
PROVISIONING_OPTIONS_STRING_DEFAULT = { PROVISIONING_OPTIONS_STRING_DEFAULT = {
@ -428,6 +431,7 @@ PROVISIONING_OPTIONS_STRING_DEFAULT = {
'fpolicy_extensions_to_exclude': None, 'fpolicy_extensions_to_exclude': None,
'fpolicy_extensions_to_include': None, 'fpolicy_extensions_to_include': None,
'fpolicy_file_operations': None, 'fpolicy_file_operations': None,
'efficiency_policy': None,
} }
SHORT_BOOLEAN_EXTRA_SPEC = { SHORT_BOOLEAN_EXTRA_SPEC = {
@ -439,6 +443,7 @@ STRING_EXTRA_SPEC = {
'netapp:language': 'en-US', 'netapp:language': 'en-US',
'netapp:max_files': 5000, 'netapp:max_files': 5000,
'netapp:adaptive_qos_policy_group': None, 'netapp:adaptive_qos_policy_group': None,
'netapp:efficiency_policy': None,
} }
SHORT_STRING_EXTRA_SPEC = { SHORT_STRING_EXTRA_SPEC = {

View File

@ -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.