diff --git a/manila/share/drivers/netapp/dataontap/client/client_cmode.py b/manila/share/drivers/netapp/dataontap/client/client_cmode.py index 52184ac7c3..d02f7b9dca 100644 --- a/manila/share/drivers/netapp/dataontap/client/client_cmode.py +++ b/manila/share/drivers/netapp/dataontap/client/client_cmode.py @@ -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 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 ce60438c49..58ff77432c 100644 --- a/manila/share/drivers/netapp/dataontap/client/client_cmode_rest.py +++ b/manila/share/drivers/netapp/dataontap/client/client_cmode_rest.py @@ -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 diff --git a/manila/share/drivers/netapp/dataontap/cluster_mode/lib_multi_svm.py b/manila/share/drivers/netapp/dataontap/cluster_mode/lib_multi_svm.py index ee9f438944..adbc0f210d 100644 --- a/manila/share/drivers/netapp/dataontap/cluster_mode/lib_multi_svm.py +++ b/manila/share/drivers/netapp/dataontap/cluster_mode/lib_multi_svm.py @@ -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) diff --git a/manila/share/drivers/netapp/options.py b/manila/share/drivers/netapp/options.py index 1d4c568d28..2102cd6a44 100644 --- a/manila/share/drivers/netapp/options.py +++ b/manila/share/drivers/netapp/options.py @@ -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, diff --git a/manila/share/manager.py b/manila/share/manager.py index 15ee4ed95b..3d7f690fb9 100644 --- a/manila/share/manager.py +++ b/manila/share/manager.py @@ -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 ' diff --git a/manila/tests/share/drivers/netapp/dataontap/client/fakes.py b/manila/tests/share/drivers/netapp/dataontap/client/fakes.py index 5bf0300a4f..1d1ed2de14 100644 --- a/manila/tests/share/drivers/netapp/dataontap/client/fakes.py +++ b/manila/tests/share/drivers/netapp/dataontap/client/fakes.py @@ -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' 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 82f741e756..9fa336d508 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 @@ -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): 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 1c89d61dd4..5724a24fdb 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 @@ -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(':', '.') diff --git a/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_multi_svm.py b/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_multi_svm.py index a8dcb7b995..64910607de 100644 --- a/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_multi_svm.py +++ b/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_multi_svm.py @@ -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() diff --git a/manila/tests/share/drivers/netapp/dataontap/fakes.py b/manila/tests/share/drivers/netapp/dataontap/fakes.py index d13fdb2361..cbbbccf24f 100644 --- a/manila/tests/share/drivers/netapp/dataontap/fakes.py +++ b/manila/tests/share/drivers/netapp/dataontap/fakes.py @@ -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') diff --git a/manila/tests/share/test_manager.py b/manila/tests/share/test_manager.py index 6ddc779836..da42d2b635 100644 --- a/manila/tests/share/test_manager.py +++ b/manila/tests/share/test_manager.py @@ -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): diff --git a/releasenotes/notes/bug-2085112-netapp-make-deleted-volumes-retention-period-configurable-403ec227f256e24b.yaml b/releasenotes/notes/bug-2085112-netapp-make-deleted-volumes-retention-period-configurable-403ec227f256e24b.yaml new file mode 100644 index 0000000000..119eec7769 --- /dev/null +++ b/releasenotes/notes/bug-2085112-netapp-make-deleted-volumes-retention-period-configurable-403ec227f256e24b.yaml @@ -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 `_