[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
This commit is contained in:
MelloCaique 2023-05-18 13:29:02 +00:00
parent b4cc96d5fd
commit bb7a06bf32
10 changed files with 167 additions and 3 deletions

View File

@ -6041,3 +6041,34 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
return self.send_request( return self.send_request(
'get-job', api_args=api_args, use_zapi=False) '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)

View File

@ -5214,3 +5214,29 @@ class NetAppRestClient(object):
'name': ipspace_name 'name': ipspace_name
} }
self.send_request('/network/ipspaces', 'delete', query=query) 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)

View File

@ -16,6 +16,7 @@
ENDPOINT_MIGRATION_ACTIONS = 'svm/migrations/%(svm_migration_id)s' ENDPOINT_MIGRATION_ACTIONS = 'svm/migrations/%(svm_migration_id)s'
ENDPOINT_MIGRATIONS = 'svm/migrations' ENDPOINT_MIGRATIONS = 'svm/migrations'
ENDPOINT_JOB_ACTIONS = 'cluster/jobs/%(job_uuid)s' ENDPOINT_JOB_ACTIONS = 'cluster/jobs/%(job_uuid)s'
ENDPOINT_MIGRATION_GET_PROGRESS = '/storage/volumes/'
endpoints = { endpoints = {
'system-get-version': { 'system-get-version': {
@ -46,4 +47,8 @@ endpoints = {
'method': 'patch', 'method': 'patch',
'url': ENDPOINT_MIGRATION_ACTIONS 'url': ENDPOINT_MIGRATION_ACTIONS
}, },
'svm-migration-get-progress': {
'method': 'get',
'url': ENDPOINT_MIGRATION_GET_PROGRESS
},
} }

View File

@ -2025,10 +2025,41 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
LOG.info('Share server migration was cancelled.') LOG.info('Share server migration was cancelled.')
@na_utils.trace
def share_server_migration_get_progress(self, context, src_share_server, def share_server_migration_get_progress(self, context, src_share_server,
dest_share_server, shares, dest_share_server, shares,
snapshots): 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} return {'total_progress': 0}
def _update_share_attributes_after_server_migration( def _update_share_attributes_after_server_migration(

View File

@ -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,
}
],
}

View File

@ -9024,3 +9024,28 @@ class NetAppClientCmodeTestCase(test.TestCase):
exception.NetAppException, exception.NetAppException,
self.client.check_snaprestore_license) self.client.check_snaprestore_license)
client_cmode.LOG.exception.assert_called_once() 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)

View File

@ -6747,3 +6747,21 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
self.assertRaises(netapp_utils.NetAppDriverException, self.assertRaises(netapp_utils.NetAppDriverException,
self.client._break_snapmirror) 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)

View File

@ -3433,12 +3433,24 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
[])) []))
def test_share_server_migration_get_progress(self): 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( 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) self.assertEqual(expected_result, result)
@ddt.data({'subtype': 'default', @ddt.data({'subtype': 'default',

View File

@ -582,6 +582,7 @@ SHARE_SERVER = {
SHARE_SERVER_2 = { SHARE_SERVER_2 = {
'id': 'fake_id_2', 'id': 'fake_id_2',
'source_share_server_id': 'fake_src_share_server_id_2',
'share_network_id': 'c5b3a865-56d0-4d88-abe5-879965e099c9', 'share_network_id': 'c5b3a865-56d0-4d88-abe5-879965e099c9',
'backend_details': { 'backend_details': {
'vserver_name': VSERVER2 'vserver_name': VSERVER2

View File

@ -0,0 +1,5 @@
---
features:
- |
NetApp driver is now able to inform the migration percentage of a share
server migration.