From bb7a06bf322e89f5b5dbdeb7421bab5f6bd5f833 Mon Sep 17 00:00:00 2001 From: MelloCaique Date: Thu, 18 May 2023 13:29:02 +0000 Subject: [PATCH] [RFE] NetApp share server migration get progress Implement method share_server_migration_get_progress to get the share server migration percent based in the total size of shares (GB) tranfered from source to destination. Depends-On: I9eae95ff3f66a3497b00ca582491afec58ae6dc3 Closes-bug: #2030969 Change-Id: If4bf3378388cc0d9ea03f58b0ab5abd9a268bfdd --- .../netapp/dataontap/client/client_cmode.py | 31 +++++++++++++++++ .../dataontap/client/client_cmode_rest.py | 26 +++++++++++++++ .../netapp/dataontap/client/rest_endpoints.py | 5 +++ .../dataontap/cluster_mode/lib_multi_svm.py | 33 ++++++++++++++++++- .../drivers/netapp/dataontap/client/fakes.py | 10 ++++++ .../dataontap/client/test_client_cmode.py | 25 ++++++++++++++ .../client/test_client_cmode_rest.py | 18 ++++++++++ .../cluster_mode/test_lib_multi_svm.py | 16 +++++++-- .../share/drivers/netapp/dataontap/fakes.py | 1 + ...app-svm-get-progress-596cd387c66dea1b.yaml | 5 +++ 10 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 releasenotes/notes/netapp-svm-get-progress-596cd387c66dea1b.yaml diff --git a/manila/share/drivers/netapp/dataontap/client/client_cmode.py b/manila/share/drivers/netapp/dataontap/client/client_cmode.py index ba1b58d7c3..576c080f76 100644 --- a/manila/share/drivers/netapp/dataontap/client/client_cmode.py +++ b/manila/share/drivers/netapp/dataontap/client/client_cmode.py @@ -6041,3 +6041,34 @@ class NetAppCmodeClient(client_base.NetAppBaseClient): return self.send_request( 'get-job', api_args=api_args, use_zapi=False) + + @na_utils.trace + def get_svm_volumes_total_size(self, svm_name): + """Gets volumes sizes sum (GB) from all volumes in SVM by svm_name""" + + request = {} + + query = { + 'svm.name': svm_name, + 'fields': 'size' + } + + api_args = self._format_request(request, query=query) + + response = self.send_request( + 'svm-migration-get-progress', api_args=api_args, use_zapi=False) + + svm_volumes = response.get('records', []) + + if len(svm_volumes) > 0: + total_volumes_size = 0 + for volume in svm_volumes: + # Root volumes are not taking account because they are part of + # SVM creation. + if volume['name'] != 'root': + total_volumes_size = total_volumes_size + volume['size'] + else: + return 0 + + # Convert Bytes to GBs. + return (total_volumes_size / 1024**3) 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 b7dd5df0d5..082889a568 100644 --- a/manila/share/drivers/netapp/dataontap/client/client_cmode_rest.py +++ b/manila/share/drivers/netapp/dataontap/client/client_cmode_rest.py @@ -5214,3 +5214,29 @@ class NetAppRestClient(object): 'name': ipspace_name } self.send_request('/network/ipspaces', 'delete', query=query) + + @na_utils.trace + def get_svm_volumes_total_size(self, svm_name): + """Gets volumes sizes sum (GB) from all volumes in SVM by svm_name""" + + query = { + 'svm.name': svm_name, + 'fields': 'size' + } + + response = self.send_request('/storage/volumes/', 'get', query=query) + + svm_volumes = response.get('records', []) + + if len(svm_volumes) > 0: + total_volumes_size = 0 + for volume in svm_volumes: + # Root volumes are not taking account because they are part of + # SVM creation. + if volume['name'] != 'root': + total_volumes_size = total_volumes_size + volume['size'] + else: + return 0 + + # Convert Bytes to GBs. + return (total_volumes_size / 1024**3) diff --git a/manila/share/drivers/netapp/dataontap/client/rest_endpoints.py b/manila/share/drivers/netapp/dataontap/client/rest_endpoints.py index 14566bc232..12443affca 100644 --- a/manila/share/drivers/netapp/dataontap/client/rest_endpoints.py +++ b/manila/share/drivers/netapp/dataontap/client/rest_endpoints.py @@ -16,6 +16,7 @@ ENDPOINT_MIGRATION_ACTIONS = 'svm/migrations/%(svm_migration_id)s' ENDPOINT_MIGRATIONS = 'svm/migrations' ENDPOINT_JOB_ACTIONS = 'cluster/jobs/%(job_uuid)s' +ENDPOINT_MIGRATION_GET_PROGRESS = '/storage/volumes/' endpoints = { 'system-get-version': { @@ -46,4 +47,8 @@ endpoints = { 'method': 'patch', 'url': ENDPOINT_MIGRATION_ACTIONS }, + 'svm-migration-get-progress': { + 'method': 'get', + 'url': ENDPOINT_MIGRATION_GET_PROGRESS + }, } 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 cc6266adea..64a47555bb 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 @@ -2025,10 +2025,41 @@ class NetAppCmodeMultiSVMFileStorageLibrary( LOG.info('Share server migration was cancelled.') + @na_utils.trace def share_server_migration_get_progress(self, context, src_share_server, dest_share_server, shares, snapshots): - # TODO(dviroel): get snapmirror info to infer the progress + """Compare source SVM total shares size with the destination SVM. + + 1. Gets the total size of the source SVM shares + 2. Gets the total size of the destination SVM shares + 3. Return the progress up to 99%, because 100% migration will be + returned when SVM migration phase 1 is finished. + """ + + # Get the total size of the source share server shares. + src_shares_total_size = 0 + for instance in shares: + src_shares_total_size = ( + src_shares_total_size + instance.get('size', 0)) + + if src_shares_total_size > 0: + # Destination share server has the same name as the source share + # server. + dest_share_server_name = self._get_vserver_name( + dest_share_server['source_share_server_id']) + + # Get current volume total size in the destination SVM. + dest_shares_total_size = self._client.get_svm_volumes_total_size( + dest_share_server_name) + + # The 100% progress will be return only when the SVM migration + # phase 1 is completed. 99% is an arbitrary number. + total_progress = ( + (99 * dest_shares_total_size) / src_shares_total_size) + + return {'total_progress': round(total_progress)} + return {'total_progress': 0} def _update_share_attributes_after_server_migration( diff --git a/manila/tests/share/drivers/netapp/dataontap/client/fakes.py b/manila/tests/share/drivers/netapp/dataontap/client/fakes.py index 9f54eefa19..b41cbebf76 100644 --- a/manila/tests/share/drivers/netapp/dataontap/client/fakes.py +++ b/manila/tests/share/drivers/netapp/dataontap/client/fakes.py @@ -4764,3 +4764,13 @@ FAKE_ROOT_AGGREGATES_RESPONSE = { } ] } + +FAKE_GET_VOLUME = { + "records": [ + { + "uuid": FAKE_UUID, + "name": "share_6cb5b3f4_35d0_40b8_a106_d35262ac17c7", + "size": 1024**3, + } + ], +} 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 03eb571885..c1debd3606 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 @@ -9024,3 +9024,28 @@ class NetAppClientCmodeTestCase(test.TestCase): exception.NetAppException, self.client.check_snaprestore_license) client_cmode.LOG.exception.assert_called_once() + + def test_get_svm_volumes_total_size(self): + expected = 1 + + request = {} + + api_args = { + 'svm.name': fake.VSERVER_NAME, + 'fields': 'size' + } + + self.mock_object(self.client, '_format_request', + mock.Mock(return_value=api_args)) + + self.mock_object(self.client, 'send_request', + mock.Mock(return_value=fake.FAKE_GET_VOLUME)) + + result = self.client.get_svm_volumes_total_size(fake.VSERVER_NAME) + + self.client._format_request.assert_called_once_with(request, + query=api_args) + self.client.send_request.assert_called_once_with( + 'svm-migration-get-progress', api_args=api_args, use_zapi=False) + + self.assertEqual(expected, result) 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 c25c3581f3..f400c5efb6 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 @@ -6747,3 +6747,21 @@ class NetAppRestCmodeClientTestCase(test.TestCase): self.assertRaises(netapp_utils.NetAppDriverException, self.client._break_snapmirror) + + def test_get_svm_volumes_total_size(self): + expected = 1 + + fake_query = { + 'svm.name': fake.VSERVER_NAME, + 'fields': 'size' + } + + self.mock_object(self.client, 'send_request', + mock.Mock(return_value=fake.FAKE_GET_VOLUME)) + + result = self.client.get_svm_volumes_total_size(fake.VSERVER_NAME) + + self.client.send_request.assert_called_once_with( + '/storage/volumes/', 'get', query=fake_query) + + self.assertEqual(expected, result) 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 6868007952..15834a220c 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 @@ -3433,12 +3433,24 @@ class NetAppFileStorageLibraryTestCase(test.TestCase): [])) def test_share_server_migration_get_progress(self): - expected_result = {'total_progress': 0} + fake_vserver_name = fake.VSERVER1 + expected_result = {'total_progress': 50} + + self.mock_object(self.library._client, 'get_svm_volumes_total_size', + mock.Mock(return_value=5)) + + self.mock_object(self.library, '_get_vserver_name', + mock.Mock(return_value=fake_vserver_name)) result = self.library.share_server_migration_get_progress( - None, None, None, None, None + None, self.fake_src_share_server, self.fake_dest_share_server, + [self.fake_src_share], None ) + self.library._client.get_svm_volumes_total_size.assert_called_once_with + (fake_vserver_name) + self.library._get_vserver_name.assert_called_once_with + (self.fake_dest_share_server['source_share_server_id']) self.assertEqual(expected_result, result) @ddt.data({'subtype': 'default', diff --git a/manila/tests/share/drivers/netapp/dataontap/fakes.py b/manila/tests/share/drivers/netapp/dataontap/fakes.py index cfc2c8fc21..55f49d2fb5 100644 --- a/manila/tests/share/drivers/netapp/dataontap/fakes.py +++ b/manila/tests/share/drivers/netapp/dataontap/fakes.py @@ -582,6 +582,7 @@ SHARE_SERVER = { SHARE_SERVER_2 = { 'id': 'fake_id_2', + 'source_share_server_id': 'fake_src_share_server_id_2', 'share_network_id': 'c5b3a865-56d0-4d88-abe5-879965e099c9', 'backend_details': { 'vserver_name': VSERVER2 diff --git a/releasenotes/notes/netapp-svm-get-progress-596cd387c66dea1b.yaml b/releasenotes/notes/netapp-svm-get-progress-596cd387c66dea1b.yaml new file mode 100644 index 0000000000..a0ff38cbeb --- /dev/null +++ b/releasenotes/notes/netapp-svm-get-progress-596cd387c66dea1b.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + NetApp driver is now able to inform the migration percentage of a share + server migration.