[Netapp] make deleted volume retention period configurable

The NetApp driver now supports user configurable volume delete
retention period (in hours). Also, the max value of share manager config
option ``unused_share_server_cleanup_interval`` is updated to possible
max value of retention period because if a share server gets deleted,
the volume recovery queue also gets purged.

Co-Authored-By: Maurice Escher <maurice.escher@sap.com>
Closes-bug: #2085112
Change-Id: I578de1ce5b162e8d378d94f1ea7ac83a394a1fcd
This commit is contained in:
Kiran Pawar 2024-10-21 14:14:43 +00:00
parent 27f3663a46
commit 998f9f24cf
12 changed files with 73 additions and 22 deletions

View File

@ -80,6 +80,7 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
ontapi_1_191 = ontapi_version >= (1, 191)
ontap_9_10 = self.get_system_version()['version-tuple'] >= (9, 10, 0)
ontap_9_10_1 = self.get_system_version()['version-tuple'] >= (9, 10, 1)
ontap_9_11_1 = self.get_system_version()['version-tuple'] >= (9, 11, 1)
self.features.add_feature('SNAPMIRROR_V2', supported=ontapi_1_20)
self.features.add_feature('SYSTEM_METRICS', supported=ontapi_1_2x)
@ -106,6 +107,8 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
self.features.add_feature('SVM_MIGRATE', supported=ontap_9_10)
self.features.add_feature('SNAPLOCK', supported=ontapi_1_100)
self.features.add_feature('UNIFIED_AGGR', supported=ontap_9_10_1)
self.features.add_feature('DELETE_RETENTION_HOURS',
supported=ontap_9_11_1)
def _invoke_vserver_api(self, na_element, vserver):
server = copy.copy(self.connection)
@ -181,10 +184,11 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
@na_utils.trace
def create_vserver(self, vserver_name, root_volume_aggregate_name,
root_volume_name, aggregate_names, ipspace_name,
security_cert_expire_days):
security_cert_expire_days, delete_retention_hours):
"""Creates new vserver and assigns aggregates."""
self._create_vserver(
vserver_name, aggregate_names, ipspace_name,
delete_retention_hours,
root_volume_name=root_volume_name,
root_volume_aggregate_name=root_volume_aggregate_name,
root_volume_security_style='unix',
@ -193,14 +197,15 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
@na_utils.trace
def create_vserver_dp_destination(self, vserver_name, aggregate_names,
ipspace_name):
ipspace_name, delete_retention_hours):
"""Creates new 'dp_destination' vserver and assigns aggregates."""
self._create_vserver(
vserver_name, aggregate_names, ipspace_name,
subtype='dp_destination')
delete_retention_hours, subtype='dp_destination')
@na_utils.trace
def _create_vserver(self, vserver_name, aggregate_names, ipspace_name,
delete_retention_hours,
root_volume_name=None, root_volume_aggregate_name=None,
root_volume_security_style=None,
name_server_switch=None, subtype=None):
@ -235,6 +240,11 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
'aggr-list': aggr_list,
'vserver-name': vserver_name,
}
if (delete_retention_hours != 0 and
self.features.DELETE_RETENTION_HOURS):
modify_args.update(
{'volume-delete-retention-hours': delete_retention_hours})
self.send_request('vserver-modify', modify_args)
@na_utils.trace

View File

@ -4347,7 +4347,7 @@ class NetAppRestClient(object):
@na_utils.trace
def create_vserver(self, vserver_name, root_volume_aggregate_name,
root_volume_name, aggregate_names, ipspace_name,
security_cert_expire_days):
security_cert_expire_days, delete_retention_hours):
"""Creates new vserver and assigns aggregates."""
# NOTE(nahimsouza): root_volume_aggregate_name and root_volume_name
@ -4355,19 +4355,20 @@ class NetAppRestClient(object):
# the vserver creation by REST API
self._create_vserver(
vserver_name, aggregate_names, ipspace_name,
name_server_switch=['files'])
delete_retention_hours, name_server_switch=['files'])
self._modify_security_cert(vserver_name, security_cert_expire_days)
@na_utils.trace
def create_vserver_dp_destination(self, vserver_name, aggregate_names,
ipspace_name):
ipspace_name, delete_retention_hours):
"""Creates new 'dp_destination' vserver and assigns aggregates."""
self._create_vserver(
vserver_name, aggregate_names, ipspace_name,
subtype='dp_destination')
delete_retention_hours, subtype='dp_destination')
@na_utils.trace
def _create_vserver(self, vserver_name, aggregate_names, ipspace_name,
delete_retention_hours,
name_server_switch=None, subtype=None):
"""Creates new vserver and assigns aggregates."""
body = {
@ -4387,6 +4388,9 @@ class NetAppRestClient(object):
for aggr_name in aggregate_names:
body['aggregates'].append({'name': aggr_name})
if delete_retention_hours != 0:
body['retention_period'] = delete_retention_hours
self.send_request('/svm/svms', 'post', body=body)
@na_utils.trace

View File

@ -333,7 +333,8 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
self._client.create_vserver_dp_destination(
vserver_name,
aggregate_names,
ipspace_name)
ipspace_name,
self.configuration.netapp_delete_retention_hours)
# Set up port and broadcast domain for the current ipspace
self._create_port_and_broadcast_domain(
ipspace_name, network_info[0])
@ -347,7 +348,8 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
self.configuration.netapp_root_volume,
aggr_set,
ipspace_name,
self.configuration.netapp_security_cert_expire_days)
self.configuration.netapp_security_cert_expire_days,
self.configuration.netapp_delete_retention_hours)
vserver_client = self._get_api_client(vserver=vserver_name)

View File

@ -107,6 +107,11 @@ netapp_provisioning_opts = [
cfg.StrOpt('netapp_root_volume',
default='root',
help='Root volume name.'),
cfg.IntOpt('netapp_delete_retention_hours',
min=0,
default=12,
help='The number of hours that a deleted volume should be '
'retained before the delete is completed.'),
cfg.IntOpt('netapp_volume_snapshot_reserve_percent',
min=0,
max=90,

View File

@ -87,7 +87,7 @@ share_manager_opts = [
cfg.IntOpt('unused_share_server_cleanup_interval',
default=10,
help='Unallocated share servers reclamation time interval '
'(minutes). Minimum value is 10 minutes, maximum is 60 '
'(minutes). Minimum value is 10 minutes, maximum is 720 '
'minutes. The reclamation function is run every '
'10 minutes and delete share servers which were unused '
'more than unused_share_server_cleanup_interval option '
@ -95,7 +95,7 @@ share_manager_opts = [
'will wait for a share server to go unutilized before '
'deleting it.',
min=10,
max=60),
max=720),
cfg.IntOpt('replica_state_update_interval',
default=300,
help='This value, specified in seconds, determines how often '

View File

@ -52,6 +52,7 @@ NODE_VSERVER_NAME = 'fake_node_vserver'
NFS_VERSIONS = ['nfs3', 'nfs4.0']
SECURITY_CERT_DEFAULT_EXPIRE_DAYS = 365
SECURITY_CERT_LARGE_EXPIRE_DAYS = 3652
DELETE_RETENTION_HOURS = 12
ROOT_AGGREGATE_NAMES = ('root_aggr1', 'root_aggr2')
ROOT_VOLUME_AGGREGATE_NAME = 'fake_root_aggr'
ROOT_VOLUME_NAME = 'fake_root_volume'

View File

@ -419,6 +419,7 @@ class NetAppClientCmodeTestCase(test.TestCase):
def test_create_vserver_no_ipspace(self):
self.client.features.add_feature('DELETE_RETENTION_HOURS')
self.mock_object(self.client, 'send_request')
self.mock_object(self.client,
'_modify_security_cert',
@ -434,7 +435,8 @@ class NetAppClientCmodeTestCase(test.TestCase):
vserver_modify_args = {
'aggr-list': [{'aggr-name': aggr_name} for aggr_name
in fake.SHARE_AGGREGATE_NAMES],
'vserver-name': fake.VSERVER_NAME
'vserver-name': fake.VSERVER_NAME,
'volume-delete-retention-hours': 16,
}
self.client.create_vserver(fake.VSERVER_NAME,
@ -442,7 +444,8 @@ class NetAppClientCmodeTestCase(test.TestCase):
fake.ROOT_VOLUME_NAME,
fake.SHARE_AGGREGATE_NAMES,
None,
fake.SECURITY_CERT_LARGE_EXPIRE_DAYS)
fake.SECURITY_CERT_LARGE_EXPIRE_DAYS,
16)
self.client.send_request.assert_has_calls([
mock.call('vserver-create', vserver_create_args),
@ -453,6 +456,7 @@ class NetAppClientCmodeTestCase(test.TestCase):
def test_create_vserver_with_ipspace(self):
self.client.features.add_feature('IPSPACES')
self.client.features.add_feature('DELETE_RETENTION_HOURS')
self.mock_object(self.client, 'send_request')
self.mock_object(self.client,
'_modify_security_cert',
@ -469,6 +473,7 @@ class NetAppClientCmodeTestCase(test.TestCase):
vserver_modify_args = {
'aggr-list': [{'aggr-name': aggr_name} for aggr_name
in fake.SHARE_AGGREGATE_NAMES],
'volume-delete-retention-hours': 24,
'vserver-name': fake.VSERVER_NAME
}
@ -477,7 +482,8 @@ class NetAppClientCmodeTestCase(test.TestCase):
fake.ROOT_VOLUME_NAME,
fake.SHARE_AGGREGATE_NAMES,
fake.IPSPACE_NAME,
fake.SECURITY_CERT_LARGE_EXPIRE_DAYS)
fake.SECURITY_CERT_LARGE_EXPIRE_DAYS,
24)
self.client.send_request.assert_has_calls([
mock.call('vserver-create', vserver_create_args),
@ -539,6 +545,7 @@ class NetAppClientCmodeTestCase(test.TestCase):
def test_create_vserver_dp_destination(self):
self.client.features.add_feature('IPSPACES')
self.client.features.add_feature('DELETE_RETENTION_HOURS')
self.mock_object(self.client, 'send_request')
vserver_create_args = {
@ -549,13 +556,15 @@ class NetAppClientCmodeTestCase(test.TestCase):
vserver_modify_args = {
'aggr-list': [{'aggr-name': aggr_name} for aggr_name
in fake.SHARE_AGGREGATE_NAMES],
'volume-delete-retention-hours': 18,
'vserver-name': fake.VSERVER_NAME
}
self.client.create_vserver_dp_destination(
fake.VSERVER_NAME,
fake.SHARE_AGGREGATE_NAMES,
fake.IPSPACE_NAME)
fake.IPSPACE_NAME,
18)
self.client.send_request.assert_has_calls([
mock.call('vserver-create', vserver_create_args),
@ -570,7 +579,8 @@ class NetAppClientCmodeTestCase(test.TestCase):
fake.ROOT_VOLUME_NAME,
fake.SHARE_AGGREGATE_NAMES,
fake.IPSPACE_NAME,
fake.SECURITY_CERT_LARGE_EXPIRE_DAYS)
fake.SECURITY_CERT_LARGE_EXPIRE_DAYS,
10)
def test_get_vserver_root_volume_name(self):

View File

@ -5029,10 +5029,12 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
self.client.create_vserver(fake.VSERVER_NAME, None, None,
[fake.SHARE_AGGREGATE_NAME],
fake.IPSPACE_NAME,
fake.SECURITY_CERT_DEFAULT_EXPIRE_DAYS)
fake.SECURITY_CERT_DEFAULT_EXPIRE_DAYS,
fake.DELETE_RETENTION_HOURS)
mock.assert_called_once_with(fake.VSERVER_NAME,
[fake.SHARE_AGGREGATE_NAME],
fake.IPSPACE_NAME,
fake.DELETE_RETENTION_HOURS,
name_server_switch=['files'])
self.client._modify_security_cert.assert_called_once_with(
fake.VSERVER_NAME,
@ -5991,12 +5993,14 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
'ipspace.name': fake.IPSPACE_NAME,
'aggregates': [{
'name': fake.SHARE_AGGREGATE_NAME
}]
}],
'retention_period': fake.DELETE_RETENTION_HOURS,
}
self.client._create_vserver(fake.VSERVER_NAME,
[fake.SHARE_AGGREGATE_NAME],
fake.IPSPACE_NAME,
fake.DELETE_RETENTION_HOURS,
fake.FAKE_SERVER_SWITCH_NAME,
fake.FAKE_SUBTYPE)
@ -6819,10 +6823,12 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
mock_vserver = self.mock_object(self.client, '_create_vserver')
self.client.create_vserver_dp_destination(fake.VSERVER_NAME,
fake.FAKE_AGGR_LIST,
fake.IPSPACE_NAME)
fake.IPSPACE_NAME,
fake.DELETE_RETENTION_HOURS)
mock_vserver.assert_called_once_with(fake.VSERVER_NAME,
fake.FAKE_AGGR_LIST,
fake.IPSPACE_NAME,
fake.DELETE_RETENTION_HOURS,
subtype='dp_destination')
@ddt.data(':', '.')

View File

@ -734,7 +734,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
self.library._client.create_vserver.assert_called_once_with(
vserver_name, fake.ROOT_VOLUME_AGGREGATE, fake.ROOT_VOLUME,
set(fake.AGGREGATES), fake.IPSPACE,
fake.SECURITY_CERT_DEFAULT_EXPIRE_DAYS)
fake.SECURITY_CERT_DEFAULT_EXPIRE_DAYS,
fake.DELETE_RETENTION_HOURS)
self.library._get_api_client.assert_called_once_with(
vserver=vserver_name)
self.library._create_vserver_lifs.assert_called_once_with(
@ -799,7 +800,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
fake.NETWORK_INFO)
create_server_mock = self.library._client.create_vserver_dp_destination
create_server_mock.assert_called_once_with(
vserver_name, fake.AGGREGATES, fake.IPSPACE)
vserver_name, fake.AGGREGATES, fake.IPSPACE,
fake.DELETE_RETENTION_HOURS)
self.library._create_port_and_broadcast_domain.assert_called_once_with(
fake.IPSPACE, fake.NETWORK_INFO)
self.library._get_flexgroup_aggr_set.assert_not_called()

View File

@ -72,6 +72,7 @@ ROOT_AGGREGATES = ('root_aggr_1', 'root_aggr_2')
ROOT_VOLUME_AGGREGATE = 'manila1'
SECURITY_CERT_DEFAULT_EXPIRE_DAYS = 365
SECURITY_CERT_LARGE_EXPIRE_DAYS = 3652
DELETE_RETENTION_HOURS = 12
ROOT_VOLUME = 'root'
CLUSTER_NODE = 'cluster1_01'
CLUSTER_NODES = ('cluster1_01', 'cluster1_02')

View File

@ -4666,7 +4666,7 @@ class ShareManagerTestCase(test.TestCase):
self.share_manager._validate_segmentation_id,
network_info)
@ddt.data(10, 36, 60)
@ddt.data(10, 36, 720)
def test_verify_server_cleanup_interval_valid_cases(self, val):
data = dict(DEFAULT=dict(unused_share_server_cleanup_interval=val))
with test_utils.create_temp_config_with_opts(data):

View File

@ -0,0 +1,10 @@
---
fixes:
- |
The NetApp ONTAP driver now supports user configurable volume delete
retention period (``netapp_volume_delete_retention_hours``). The max value
of config option ``unused_share_server_cleanup_interval`` is updated to
possible max value of retention period because if a share server gets
deleted, the volume recovery queue also gets purged.
For more details, please check
`Launchpad bug #2085112 <https://bugs.launchpad.net/manila/+bug/2085112>`_