Human readable export location NetApp driver changes

NetApp driver changes to accommodate human readable
share location. Export path is updated with
human frendly value if present else use share-id.

partially-implements: bp human-readable-export-locations
Depends-On: I72ac7e24ddd4330d76cafd5e7f78bac2b0174883
Change-Id: I2f5bfdbc9d0458c7b9198a3eb94b3b095d5b5e04
This commit is contained in:
jayaanand.borra@netapp.com 2024-02-13 17:17:34 +05:30 committed by jayaanand borra
parent d4fb4319f5
commit 4f36847de9
9 changed files with 136 additions and 60 deletions

View File

@ -2215,7 +2215,7 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
compression_enabled=False, max_files=None,
snapshot_reserve=None, volume_type='rw',
qos_policy_group=None, adaptive_qos_policy_group=None,
encrypt=False, **options):
encrypt=False, mount_point_name=None, **options):
"""Creates a volume."""
if adaptive_qos_policy_group and not self.features.ADAPTIVE_QOS:
msg = 'Adaptive QoS not supported on this backend ONTAP version.'
@ -2229,7 +2229,7 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
api_args.update(self._get_create_volume_api_args(
volume_name, thin_provisioned, snapshot_policy, language,
snapshot_reserve, volume_type, qos_policy_group, encrypt,
adaptive_qos_policy_group))
adaptive_qos_policy_group, mount_point_name))
self.send_request('volume-create', api_args)
@ -2245,7 +2245,8 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
language=None, snapshot_reserve=None,
volume_type='rw', qos_policy_group=None,
encrypt=False, adaptive_qos_policy_group=None,
auto_provisioned=False, **options):
auto_provisioned=False, mount_point_name=None,
**options):
"""Creates a volume asynchronously."""
if adaptive_qos_policy_group and not self.features.ADAPTIVE_QOS:
@ -2264,7 +2265,7 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
api_args.update(self._get_create_volume_api_args(
volume_name, thin_provisioned, snapshot_policy, language,
snapshot_reserve, volume_type, qos_policy_group, encrypt,
adaptive_qos_policy_group))
adaptive_qos_policy_group, mount_point_name))
result = self.send_request('volume-create-async', api_args)
job_info = {
@ -2279,13 +2280,15 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
snapshot_policy, language,
snapshot_reserve, volume_type,
qos_policy_group, encrypt,
adaptive_qos_policy_group):
adaptive_qos_policy_group,
mount_point_name=None):
api_args = {
'volume-type': volume_type,
'space-reserve': ('none' if thin_provisioned else 'volume'),
}
if volume_type != 'dp':
api_args['junction-path'] = '/%s' % volume_name
api_args['junction-path'] = '/%s' % (mount_point_name
or volume_name)
if snapshot_policy is not None:
api_args['snapshot-policy'] = snapshot_policy
if language is not None:

View File

@ -953,7 +953,7 @@ class NetAppRestClient(object):
compression_enabled=False, max_files=None,
snapshot_reserve=None, volume_type='rw',
qos_policy_group=None, adaptive_qos_policy_group=None,
encrypt=False, **options):
encrypt=False, mount_point_name=None, **options):
"""Creates a FlexVol volume synchronously."""
# NOTE(nahimsouza): In REST API, both FlexVol and FlexGroup volumes are
@ -966,7 +966,8 @@ class NetAppRestClient(object):
language=language, max_files=max_files,
snapshot_reserve=snapshot_reserve, volume_type=volume_type,
qos_policy_group=qos_policy_group, encrypt=encrypt,
adaptive_qos_policy_group=adaptive_qos_policy_group, **options)
adaptive_qos_policy_group=adaptive_qos_policy_group,
mount_point_name=mount_point_name, **options)
self.update_volume_efficiency_attributes(volume_name,
dedup_enabled,
@ -981,7 +982,8 @@ class NetAppRestClient(object):
language=None, snapshot_reserve=None,
volume_type='rw', qos_policy_group=None,
encrypt=False, adaptive_qos_policy_group=None,
auto_provisioned=False, **options):
auto_provisioned=False, mount_point_name=None,
**options):
"""Creates FlexGroup/FlexVol volumes.
If the parameter `is_flexgroup` is False, the creation process is
@ -1002,7 +1004,7 @@ class NetAppRestClient(object):
body.update(self._get_create_volume_body(
volume_name, thin_provisioned, snapshot_policy, language,
snapshot_reserve, volume_type, qos_policy_group, encrypt,
adaptive_qos_policy_group))
adaptive_qos_policy_group, mount_point_name))
# NOTE(nahimsouza): When a volume is not a FlexGroup, volume creation
# is made synchronously to replicate old ZAPI behavior. When ZAPI is
@ -1025,7 +1027,8 @@ class NetAppRestClient(object):
def _get_create_volume_body(self, volume_name, thin_provisioned,
snapshot_policy, language, snapshot_reserve,
volume_type, qos_policy_group, encrypt,
adaptive_qos_policy_group):
adaptive_qos_policy_group,
mount_point_name=None):
"""Builds the body to volume creation request."""
body = {
@ -1034,7 +1037,8 @@ class NetAppRestClient(object):
'svm.name': self.connection.get_vserver()
}
if volume_type != 'dp':
body['nas.path'] = f'/{volume_name}'
mount_point_name = mount_point_name or volume_name
body['nas.path'] = f'/{mount_point_name}'
if snapshot_policy is not None:
body['snapshot_policy.name'] = snapshot_policy
if language is not None:

View File

@ -550,7 +550,8 @@ class NetAppCmodeFileStorageLibrary(object):
'create_share_from_snapshot_support': True,
'revert_to_snapshot_support': self._revert_to_snapshot_support,
'security_service_update_support': True,
'share_server_multiple_subnet_support': True
'share_server_multiple_subnet_support': True,
'mount_point_name_support': True
}
# Add storage service catalog data.
@ -1130,6 +1131,7 @@ class NetAppCmodeFileStorageLibrary(object):
provisioning_options['volume_type'] = 'dp'
hide_snapdir = provisioning_options.pop('hide_snapdir')
mount_point_name = share.get('mount_point_name')
LOG.debug('Creating share %(share)s on pool %(pool)s with '
'provisioning options %(options)s',
@ -1141,12 +1143,15 @@ class NetAppCmodeFileStorageLibrary(object):
vserver_client, aggr_list, share_name,
share['size'],
self.configuration.netapp_volume_snapshot_reserve_percent,
mount_point_name=mount_point_name,
**provisioning_options)
else:
vserver_client.create_volume(
pool_name, share_name, share['size'],
snapshot_reserve=self.configuration.
netapp_volume_snapshot_reserve_percent, **provisioning_options)
netapp_volume_snapshot_reserve_percent,
mount_point_name=mount_point_name,
**provisioning_options)
if hide_snapdir:
self._apply_snapdir_visibility(
@ -1174,14 +1179,14 @@ class NetAppCmodeFileStorageLibrary(object):
def _create_flexgroup_share(self, vserver_client, aggr_list, share_name,
size, snapshot_reserve, dedup_enabled=False,
compression_enabled=False, max_files=None,
**provisioning_options):
mount_point_name=None, **provisioning_options):
"""Create a FlexGroup share using async API with job."""
start_timeout = (
self.configuration.netapp_flexgroup_aggregate_not_busy_timeout)
job_info = self.wait_for_start_create_flexgroup(
start_timeout, vserver_client, aggr_list, share_name, size,
snapshot_reserve, **provisioning_options)
snapshot_reserve, mount_point_name, **provisioning_options)
if not job_info['jobid'] or job_info['error-code']:
msg = "Error creating FlexGroup share: %s."
@ -1201,6 +1206,7 @@ class NetAppCmodeFileStorageLibrary(object):
def wait_for_start_create_flexgroup(self, start_timeout, vserver_client,
aggr_list, share_name, size,
snapshot_reserve,
mount_point_name=None,
**provisioning_options):
"""Wait for starting create FlexGroup volume succeed.
@ -1214,6 +1220,7 @@ class NetAppCmodeFileStorageLibrary(object):
:param share_name: name of the FlexGroup volume.
:param size: size to be provisioned.
:param snapshot_reserve: snapshot reserve option.
:param mount_point_name: junction_path_name.
:param provisioning_options: other provision not required options.
"""
@ -1225,9 +1232,11 @@ class NetAppCmodeFileStorageLibrary(object):
def _start_create_flexgroup_volume():
try:
return vserver_client.create_volume_async(
aggr_list, share_name, size, is_flexgroup=True,
aggr_list, share_name, size,
is_flexgroup=True,
snapshot_reserve=snapshot_reserve,
auto_provisioned=self._is_flexgroup_auto,
mount_point_name=mount_point_name,
**provisioning_options)
except netapp_api.NaApiError as e:
with excutils.save_and_reraise_exception() as raise_ctxt:
@ -2027,6 +2036,7 @@ class NetAppCmodeFileStorageLibrary(object):
reason=msg % msg_args)
share_name = self._get_backend_share_name(share['id'])
mount_point_name = share.get('mount_point_name')
debug_args = {
'share': share_name,
'aggr': (",".join(aggregate_name) if flexgroup_vol
@ -2039,7 +2049,7 @@ class NetAppCmodeFileStorageLibrary(object):
# Rename & remount volume on new path.
vserver_client.unmount_volume(volume_name)
vserver_client.set_volume_name(volume_name, share_name)
vserver_client.mount_volume(share_name)
vserver_client.mount_volume(share_name, mount_point_name)
qos_policy_group_name = self._modify_or_create_qos_for_existing_share(
share, extra_specs, vserver, vserver_client)
@ -3942,12 +3952,13 @@ class NetAppCmodeFileStorageLibrary(object):
def _rehost_and_mount_volume(self, share, src_vserver, src_vserver_client,
dest_vserver, dest_vserver_client):
volume_name = self._get_backend_share_name(share['id'])
mount_point_name = share.get('mount_point_name')
# Unmount volume in the source vserver:
src_vserver_client.unmount_volume(volume_name)
# Rehost the volume
self.volume_rehost(share, src_vserver, dest_vserver)
# Mount the volume on the destination vserver
dest_vserver_client.mount_volume(volume_name)
dest_vserver_client.mount_volume(volume_name, mount_point_name)
def _check_capacity_compatibility(self, pools, thin_provision, size):
"""Check if the size requested is suitable for the available pools"""

View File

@ -65,37 +65,31 @@ class ShareTransferAPITestCase(test.TestCase):
mount_point_name=None):
"""Create a share object."""
share_type = db_utils.create_share_type()
instance_list = []
if mount_point_name:
instance_list = [
instance_list.append(
db_utils.create_share_instance(
status=status,
share_id='fake_id',
mount_point_name=mount_point_name
)
]
share = db_utils.create_share(
display_name=display_name,
display_description=display_description,
status=status, size=size,
project_id=project_id,
user_id=user_id,
share_type_id=share_type['id'],
share_network_id=share_network_id,
instances=instance_list
)
else:
share = db_utils.create_share(
display_name=display_name,
display_description=display_description,
status=status,
size=size,
project_id=project_id,
user_id=user_id,
share_type_id=share_type['id'],
share_network_id=share_network_id,
mount_point_name=mount_point_name
)
share = db_utils.create_share(
display_name=display_name,
display_description=display_description,
status=status,
size=size,
project_id=project_id,
user_id=user_id,
share_type_id=share_type['id'],
share_network_id=share_network_id,
instances=instance_list,
mount_point_name=mount_point_name
)
share_id = share['id']
return share_id
def test_show_transfer(self):
@ -276,9 +270,7 @@ class ShareTransferAPITestCase(test.TestCase):
def test_create_transfer_with_project_id_prefix_mount_point_name(self):
share_id = self._create_share(project_id='fake',
mount_point_name='fake_mp')
'''self.share_transfer_api.create(context.get_admin_context(),
share_id,
'test_missing_share_type')'''
self.assertRaises(exception.Invalid,
self.share_transfer_api.create,
context.get_admin_context(), share_id,

View File

@ -3215,7 +3215,8 @@ class NetAppClientCmodeTestCase(test.TestCase):
}
self.client._get_create_volume_api_args.assert_called_once_with(
fake.SHARE_NAME, False, None, None, None, 'rw', None, False, None)
fake.SHARE_NAME, False, None, None, None, 'rw', None, False,
None, None)
self.client.send_request.assert_called_with('volume-create',
volume_create_args)
(self.client.update_volume_efficiency_attributes.
@ -3291,7 +3292,8 @@ class NetAppClientCmodeTestCase(test.TestCase):
}
self.client._get_create_volume_api_args.assert_called_once_with(
fake.SHARE_NAME, False, None, None, None, 'rw', None, False, None)
fake.SHARE_NAME, False, None, None, None, 'rw', None, False,
None, None)
self.client.send_request.assert_called_with('volume-create-async',
volume_create_args)
self.assertEqual(expected_result, result)
@ -3308,6 +3310,37 @@ class NetAppClientCmodeTestCase(test.TestCase):
adaptive_qos_policy_group='fake')
self.client.send_request.assert_not_called()
def test_get_create_volume_api_args_with_mount_point_name(self):
self.client.features.add_feature('FLEXVOL_ENCRYPTION')
volume_type = 'rw'
thin_provisioned = False
snapshot_policy = 'default'
language = 'en-US'
reserve = 15
qos_name = 'fake_qos'
encrypt = True
qos_adaptive_name = 'fake_adaptive_qos'
mount_point_name = 'fake_mp'
result_api_args = self.client._get_create_volume_api_args(
fake.SHARE_NAME, thin_provisioned, snapshot_policy, language,
reserve, volume_type, qos_name, encrypt, qos_adaptive_name,
mount_point_name)
expected_api_args = {
'volume-type': volume_type,
'junction-path': '/fake_mp',
'space-reserve': 'volume',
'snapshot-policy': snapshot_policy,
'language-code': language,
'percentage-snapshot-reserve': str(reserve),
'qos-policy-group-name': qos_name,
'qos-adaptive-policy-group-name': qos_adaptive_name,
'encrypt': 'true',
}
self.assertEqual(expected_api_args, result_api_args)
def test_get_create_volume_api_args_with_extra_specs(self):
self.client.features.add_feature('FLEXVOL_ENCRYPTION')

View File

@ -1045,7 +1045,7 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
is_flexgroup=False, thin_provisioned=False, snapshot_policy=None,
language=None, max_files=1, snapshot_reserve=None,
volume_type='rw', qos_policy_group=None, encrypt=False,
adaptive_qos_policy_group=None)
adaptive_qos_policy_group=None, mount_point_name=None)
mock_update.assert_called_once_with(fake.VOLUME_NAMES[0], False, False)
mock_max_files.assert_called_once_with(fake.VOLUME_NAMES[0], 1)
@ -1076,7 +1076,7 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
self.client._get_create_volume_body.assert_called_once_with(
fake.VOLUME_NAMES[0], False, None, None, None, 'rw', None, False,
None)
None, None)
self.client.send_request.assert_called_once_with(
'/storage/volumes', 'post', body=body, wait_on_accepted=True)
self.assertEqual(expected_result, result)
@ -2602,7 +2602,7 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
permission = record['permission']
rules[user_or_group] = permission
def test_mount_volume(self):
def test_mount_volume_with_junction_path(self):
volume_name = fake.SHARE_NAME
junction_path = '/fake_path'
volume = fake.VOLUME
@ -2616,8 +2616,26 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
uuid = volume['uuid']
body = {
'nas.path': (junction_path if junction_path
else '/%s' % volume_name)
'nas.path': junction_path
}
self.client.send_request.assert_called_once_with(
f'/storage/volumes/{uuid}', 'patch', body=body)
def test_mount_volume_with_volume_name(self):
volume_name = fake.SHARE_NAME
volume = fake.VOLUME
self.mock_object(self.client, '_get_volume_by_args',
mock.Mock(return_value=volume))
self.mock_object(self.client, 'send_request')
self.client.mount_volume(volume_name)
uuid = volume['uuid']
body = {
'nas.path': '/%s' % volume_name
}
self.client.send_request.assert_called_once_with(

View File

@ -1537,12 +1537,14 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
mock_get_aggr_flexgroup.assert_called_once_with(fake.POOL_NAME)
mock_create_flexgroup.assert_called_once_with(
vserver_client, [fake.AGGREGATE], fake.SHARE_NAME,
fake.SHARE['size'], 8, **provisioning_options)
fake.SHARE['size'], 8, mount_point_name=fake.MOUNT_POINT_NAME,
**provisioning_options)
else:
mock_get_aggr_flexgroup.assert_not_called()
vserver_client.create_volume.assert_called_once_with(
fake.POOL_NAME, fake.SHARE_NAME, fake.SHARE['size'],
snapshot_reserve=8, **provisioning_options)
snapshot_reserve=8, mount_point_name=fake.MOUNT_POINT_NAME,
**provisioning_options)
if hide_snapdir:
vserver_client.set_volume_snapdir_access.assert_called_once_with(
@ -1587,8 +1589,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
thin_provisioned=True, snapshot_policy='default',
language='en-US', dedup_enabled=True, split=True,
compression_enabled=False, max_files=5000, encrypt=False,
snapshot_reserve=8, volume_type='dp',
adaptive_qos_policy_group=None)
snapshot_reserve=8, mount_point_name=fake.MOUNT_POINT_NAME,
volume_type='dp', adaptive_qos_policy_group=None)
def test_allocate_container_no_pool_name(self):
self.mock_object(self.library, '_get_backend_share_name', mock.Mock(
@ -1630,7 +1632,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
start_timeout = (self.library.configuration.
netapp_flexgroup_aggregate_not_busy_timeout)
mock_wait_for_start.assert_called_once_with(
start_timeout, vserver_client, aggr_list, fake.SHARE_NAME, 100, 10)
start_timeout, vserver_client, aggr_list, fake.SHARE_NAME, 100,
10, None)
mock_wait_for_flexgroup_deployment.assert_called_once_with(
vserver_client, fake.JOB_ID, 2)
(vserver_client.update_volume_efficiency_attributes.
@ -1668,7 +1671,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
vserver_client.create_volume_async.assert_called_once_with(
aggr_list, fake.SHARE_NAME, 1, is_flexgroup=True,
snapshot_reserve=10,
auto_provisioned=self.library._is_flexgroup_auto)
auto_provisioned=self.library._is_flexgroup_auto,
mount_point_name=None)
def test_wait_for_start_create_flexgroup_timeout(self):
vserver_client = mock.Mock()
@ -2809,7 +2813,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
vserver_client.set_volume_name.assert_called_once_with(
fake.FLEXVOL_NAME, fake.SHARE_NAME)
vserver_client.mount_volume.assert_called_once_with(
fake.SHARE_NAME)
fake.SHARE_NAME, fake.MOUNT_POINT_NAME)
vserver_client.modify_volume.assert_called_once_with(
fake_aggr, fake.SHARE_NAME, **provisioning_opts)
mock_modify_or_create_qos_policy.assert_called_once_with(
@ -7124,7 +7128,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
mock_unmount.assert_called_once_with(fake.SHARE_NAME)
mock_rehost.assert_called_once_with(fake.SHARE, fake.VSERVER1,
fake.VSERVER2)
mock_mount.assert_called_once_with(fake.SHARE_NAME)
mock_mount.assert_called_once_with(fake.SHARE_NAME,
fake.MOUNT_POINT_NAME)
def test__move_volume_after_splitting(self):
src_share = fake_share.fake_share_instance(id='source-share-instance')

View File

@ -114,6 +114,7 @@ FPOLICY_EXT_TO_INCLUDE_LIST = ['avi']
FPOLICY_EXT_TO_EXCLUDE = 'jpg,mp3'
FPOLICY_EXT_TO_EXCLUDE_LIST = ['jpg', 'mp3']
BACKUP_TYPE = "fake_backup_type"
MOUNT_POINT_NAME = 'fake_mp'
JOB_ID = '123'
JOB_STATE = 'success'
@ -135,6 +136,7 @@ SHARE = {
'host': MANILA_HOST_NAME,
'project_id': TENANT_ID,
'name': SHARE_NAME,
'mount_point_name': MOUNT_POINT_NAME,
'size': SHARE_SIZE,
'share_proto': 'fake',
'share_type_id': 'fake_share_type_id',
@ -195,6 +197,7 @@ SHARE_INSTANCE = {
'share_id': SHARE_ID,
'host': MANILA_HOST_NAME,
'project_id': TENANT_ID,
'mount_point_name': MOUNT_POINT_NAME,
'name': SHARE_INSTANCE_NAME,
'size': SHARE_SIZE,
'share_proto': 'fake',
@ -1037,6 +1040,7 @@ POOLS = [
'utilization': 30.0,
'filter_function': 'filter',
'goodness_function': 'goodness',
'mount_point_name_support': True,
'snapshot_support': True,
'create_share_from_snapshot_support': True,
'revert_to_snapshot_support': True,
@ -1082,6 +1086,7 @@ POOLS_VSERVER_CREDS = [
'pool_name': AGGREGATES[0],
'filter_function': None,
'goodness_function': None,
'mount_point_name_support': True,
'netapp_cluster_name': '',
'netapp_aggregate': AGGREGATES[0],
'total_capacity_gb': 'unknown',

View File

@ -0,0 +1,5 @@
features:
- |
The NetApp ONTAP driver now supports the common capability
"mount_point_name_support". It allows users to
specify a custom "mount_point_name" when creating shares.