[NetApp] Enables configuring NFS transfer limits
From this this change, shares and share groups can be created upon share servers configured with specific NFS max transfer limits. An administrator is now able to set the share type extra-specs `netapp:udp_max_xfer_size` and `netapp:tcp_max_xfer_size`. While creating a share server or providing a share server to a share or a share group, the NetApp driver will consider these extra-specs to decide whether to create or reuse a share server. Share server now contains the details:nfs_config field, which stores the server NFS configuration dictionary. In case the server does not have a NFS configuration requirement, it saves the default NFS values, retrieved at the driver startup. A server without details:nfs_config is considered as using the default one. The share server manage operation was modified to also retrieve its NFS max transfer configurations. The share manage operation was modified to check whether the NFS max transfer extra-specs are matching the share server configured values. It relies on ONTAP features available only in versions equal and greater than ``9.4``. Implements: bp netapp-share-server-nfs-modify Change-Id: Iaddb771ae28ec59dd125af0bf638f591f5662bfc Depends-On: I8daf919a764075998be95c5845807bec37104c78
This commit is contained in:
parent
636f255546
commit
78ca06d6b8
@ -70,6 +70,7 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
||||
ontapi_1_2x = (1, 20) <= ontapi_version < (1, 30)
|
||||
ontapi_1_30 = ontapi_version >= (1, 30)
|
||||
ontapi_1_110 = ontapi_version >= (1, 110)
|
||||
ontapi_1_140 = ontapi_version >= (1, 140)
|
||||
ontapi_1_150 = ontapi_version >= (1, 150)
|
||||
|
||||
self.features.add_feature('SNAPMIRROR_V2', supported=ontapi_1_20)
|
||||
@ -83,6 +84,8 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
||||
self.features.add_feature('ADVANCED_DISK_PARTITIONING',
|
||||
supported=ontapi_1_30)
|
||||
self.features.add_feature('FLEXVOL_ENCRYPTION', supported=ontapi_1_110)
|
||||
self.features.add_feature('TRANSFER_LIMIT_NFS_CONFIG',
|
||||
supported=ontapi_1_140)
|
||||
self.features.add_feature('CIFS_DC_ADD_SKIP_CHECK',
|
||||
supported=ontapi_1_150)
|
||||
|
||||
@ -1352,10 +1355,14 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
||||
raise exception.NetAppException(msg % security_service['type'])
|
||||
|
||||
@na_utils.trace
|
||||
def enable_nfs(self, versions):
|
||||
def enable_nfs(self, versions, nfs_config=None):
|
||||
"""Enables NFS on Vserver."""
|
||||
self.send_request('nfs-enable')
|
||||
self._enable_nfs_protocols(versions)
|
||||
|
||||
if nfs_config:
|
||||
self._configure_nfs(nfs_config)
|
||||
|
||||
self._create_default_nfs_export_rules()
|
||||
|
||||
@na_utils.trace
|
||||
@ -1372,6 +1379,11 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
||||
}
|
||||
self.send_request('nfs-service-modify', nfs_service_modify_args)
|
||||
|
||||
@na_utils.trace
|
||||
def _configure_nfs(self, nfs_config):
|
||||
"""Sets the nfs configuraton"""
|
||||
self.send_request('nfs-service-modify', nfs_config)
|
||||
|
||||
@na_utils.trace
|
||||
def _create_default_nfs_export_rules(self):
|
||||
"""Create the default export rule for the NFS service."""
|
||||
@ -4033,3 +4045,44 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
||||
'destination-vserver': destination_vserver,
|
||||
}
|
||||
self.send_request('volume-rehost', api_args)
|
||||
|
||||
@na_utils.trace
|
||||
def get_nfs_config(self, desired_args, vserver):
|
||||
"""Gets the NFS config of the given vserver with the desired params"""
|
||||
api_args = {
|
||||
'query': {
|
||||
'nfs-info': {
|
||||
'vserver': vserver,
|
||||
},
|
||||
},
|
||||
}
|
||||
nfs_info = {}
|
||||
for arg in desired_args:
|
||||
nfs_info[arg] = None
|
||||
|
||||
if nfs_info:
|
||||
api_args['desired-attributes'] = {'nfs-info': nfs_info}
|
||||
|
||||
result = self.send_request('nfs-service-get-iter', api_args)
|
||||
child_elem = result.get_child_by_name('attributes-list')
|
||||
|
||||
return self.parse_nfs_config(child_elem, desired_args)
|
||||
|
||||
@na_utils.trace
|
||||
def get_nfs_config_default(self, desired_args):
|
||||
"""Gets the default NFS config with the desired params"""
|
||||
result = self.send_request('nfs-service-get-create-defaults', None)
|
||||
child_elem = result.get_child_by_name('defaults')
|
||||
|
||||
return self.parse_nfs_config(child_elem, desired_args)
|
||||
|
||||
@na_utils.trace
|
||||
def parse_nfs_config(self, parent_elem, desired_args):
|
||||
"""Parse the get NFS config operation returning the desired params"""
|
||||
nfs_info_elem = parent_elem.get_child_by_name('nfs-info')
|
||||
|
||||
nfs_config = {}
|
||||
for arg in desired_args:
|
||||
nfs_config[arg] = nfs_info_elem.get_child_content(arg)
|
||||
|
||||
return nfs_config
|
||||
|
@ -286,3 +286,18 @@ class NetAppCmodeMultiSvmShareDriver(driver.ShareDriver):
|
||||
|
||||
def get_share_status(self, share_instance, share_server=None):
|
||||
return self.library.get_share_status(share_instance, share_server)
|
||||
|
||||
def choose_share_server_compatible_with_share(self, context,
|
||||
share_servers, share,
|
||||
snapshot=None,
|
||||
share_group=None):
|
||||
return self.library.choose_share_server_compatible_with_share(
|
||||
context, share_servers, share, snapshot=snapshot,
|
||||
share_group=share_group)
|
||||
|
||||
def choose_share_server_compatible_with_share_group(
|
||||
self, context, share_servers, share_group_ref,
|
||||
share_group_snapshot=None):
|
||||
return self.library.choose_share_server_compatible_with_share_group(
|
||||
context, share_servers, share_group_ref,
|
||||
share_group_snapshot=share_group_snapshot)
|
||||
|
@ -283,3 +283,13 @@ class NetAppCmodeSingleSvmShareDriver(driver.ShareDriver):
|
||||
|
||||
def get_share_status(self, share_instance, share_server=None):
|
||||
return self.library.get_share_status(share_instance, share_server)
|
||||
|
||||
def choose_share_server_compatible_with_share(self, context, share_servers,
|
||||
share, snapshot=None,
|
||||
share_group=None):
|
||||
raise NotImplementedError
|
||||
|
||||
def choose_share_server_compatible_with_share_group(
|
||||
self, context, share_servers, share_group_ref,
|
||||
share_group_snapshot=None):
|
||||
raise NotImplementedError
|
||||
|
@ -108,6 +108,13 @@ class NetAppCmodeFileStorageLibrary(object):
|
||||
|
||||
SIZE_DEPENDENT_QOS_SPECS = {'maxiopspergib', 'maxbpspergib'}
|
||||
|
||||
# Maps the NFS config used by share-servers
|
||||
NFS_CONFIG_EXTRA_SPECS_MAP = {
|
||||
|
||||
'netapp:tcp_max_xfer_size': 'tcp-max-xfer-size',
|
||||
'netapp:udp_max_xfer_size': 'udp-max-xfer-size',
|
||||
}
|
||||
|
||||
def __init__(self, driver_name, **kwargs):
|
||||
na_utils.validate_driver_instantiation(**kwargs)
|
||||
|
||||
@ -132,6 +139,8 @@ class NetAppCmodeFileStorageLibrary(object):
|
||||
self._have_cluster_creds = None
|
||||
self._revert_to_snapshot_support = False
|
||||
self._cluster_info = {}
|
||||
self._default_nfs_config = None
|
||||
self.is_nfs_config_supported = False
|
||||
|
||||
self._app_version = kwargs.get('app_version', 'unknown')
|
||||
|
||||
@ -153,6 +162,17 @@ class NetAppCmodeFileStorageLibrary(object):
|
||||
# Performance monitoring library
|
||||
self._perf_library = performance.PerformanceLibrary(self._client)
|
||||
|
||||
# NOTE(felipe_rodrigues): In case adding a parameter that can be
|
||||
# configured in old versions too, the "is_nfs_config_supported" should
|
||||
# be removed (always supporting), adding the logic of skipping the
|
||||
# transfer limit parameters when building the server nfs_config.
|
||||
if self._client.features.TRANSFER_LIMIT_NFS_CONFIG:
|
||||
self.is_nfs_config_supported = True
|
||||
self._default_nfs_config = self._client.get_nfs_config_default(
|
||||
list(self.NFS_CONFIG_EXTRA_SPECS_MAP.values()))
|
||||
LOG.debug('The default NFS configuration: %s',
|
||||
self._default_nfs_config)
|
||||
|
||||
@na_utils.trace
|
||||
def _set_cluster_info(self):
|
||||
self._cluster_info['nve_support'] = (
|
||||
@ -929,7 +949,7 @@ class NetAppCmodeFileStorageLibrary(object):
|
||||
return dict(zip(provisioning_args, provisioning_values))
|
||||
|
||||
@na_utils.trace
|
||||
def _get_string_provisioning_options(self, specs, string_specs_map):
|
||||
def get_string_provisioning_options(self, specs, string_specs_map):
|
||||
"""Given extra specs, return corresponding client library kwargs.
|
||||
|
||||
Build a full set of client library provisioning kwargs, filling in a
|
||||
@ -1027,7 +1047,7 @@ class NetAppCmodeFileStorageLibrary(object):
|
||||
boolean_args = self._get_boolean_provisioning_options(
|
||||
specs, self.BOOLEAN_QUALIFIED_EXTRA_SPECS_MAP)
|
||||
|
||||
string_args = self._get_string_provisioning_options(
|
||||
string_args = self.get_string_provisioning_options(
|
||||
specs, self.STRING_QUALIFIED_EXTRA_SPECS_MAP)
|
||||
result = boolean_args.copy()
|
||||
result.update(string_args)
|
||||
@ -2330,6 +2350,12 @@ class NetAppCmodeFileStorageLibrary(object):
|
||||
destination_share)
|
||||
self._check_extra_specs_validity(
|
||||
destination_share, extra_specs)
|
||||
|
||||
# NOTE (felipe_rodrigues): NetApp only can migrate within the
|
||||
# same server, so it does not need to check that the
|
||||
# destination share has the same NFS config as the destination
|
||||
# server.
|
||||
|
||||
# TODO(gouthamr): Check whether QoS min-throughputs can be
|
||||
# honored on the destination aggregate when supported.
|
||||
self._check_aggregate_extra_specs_validity(
|
||||
|
@ -33,6 +33,7 @@ from manila.share.drivers.netapp.dataontap.client import client_cmode
|
||||
from manila.share.drivers.netapp.dataontap.cluster_mode import data_motion
|
||||
from manila.share.drivers.netapp.dataontap.cluster_mode import lib_base
|
||||
from manila.share.drivers.netapp import utils as na_utils
|
||||
from manila.share import share_types
|
||||
from manila.share import utils as share_utils
|
||||
from manila import utils
|
||||
|
||||
@ -123,12 +124,19 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
|
||||
@na_utils.trace
|
||||
def setup_server(self, network_info, metadata=None):
|
||||
"""Creates and configures new Vserver."""
|
||||
|
||||
vlan = network_info['segmentation_id']
|
||||
ports = {}
|
||||
for network_allocation in network_info['network_allocations']:
|
||||
ports[network_allocation['id']] = network_allocation['ip_address']
|
||||
|
||||
nfs_config = self._default_nfs_config
|
||||
if (self.is_nfs_config_supported and metadata and
|
||||
'share_type_id' in metadata):
|
||||
extra_specs = share_types.get_share_type_extra_specs(
|
||||
metadata['share_type_id'])
|
||||
self._check_nfs_config_extra_specs_validity(extra_specs)
|
||||
nfs_config = self._get_nfs_config_provisioning_options(extra_specs)
|
||||
|
||||
@utils.synchronized('netapp-VLAN-%s' % vlan, external=True)
|
||||
def setup_server_with_lock():
|
||||
LOG.debug('Creating server %s', network_info['server_id'])
|
||||
@ -137,11 +145,15 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
|
||||
vserver_name = self._get_vserver_name(network_info['server_id'])
|
||||
server_details = {
|
||||
'vserver_name': vserver_name,
|
||||
'ports': jsonutils.dumps(ports)
|
||||
'ports': jsonutils.dumps(ports),
|
||||
}
|
||||
|
||||
if self.is_nfs_config_supported:
|
||||
server_details['nfs_config'] = jsonutils.dumps(nfs_config)
|
||||
|
||||
try:
|
||||
self._create_vserver(vserver_name, network_info)
|
||||
self._create_vserver(vserver_name, network_info,
|
||||
nfs_config=nfs_config)
|
||||
except Exception as e:
|
||||
e.detail_data = {'server_details': server_details}
|
||||
raise
|
||||
@ -150,6 +162,38 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
|
||||
|
||||
return setup_server_with_lock()
|
||||
|
||||
@na_utils.trace
|
||||
def _check_nfs_config_extra_specs_validity(self, extra_specs):
|
||||
"""Check if the nfs config extra_spec has valid values."""
|
||||
int_extra_specs = ['netapp:tcp_max_xfer_size',
|
||||
'netapp:udp_max_xfer_size']
|
||||
for key in int_extra_specs:
|
||||
if key in extra_specs:
|
||||
self._check_if_extra_spec_is_positive(
|
||||
extra_specs[key], key)
|
||||
|
||||
@na_utils.trace
|
||||
def _check_if_extra_spec_is_positive(self, value, key):
|
||||
"""Check if extra_spec has a valid positive int value."""
|
||||
if int(value) < 0:
|
||||
args = {'value': value, 'key': key}
|
||||
msg = _('Invalid value "%(value)s" for extra_spec "%(key)s" '
|
||||
'used by share server setup.')
|
||||
raise exception.NetAppException(msg % args)
|
||||
|
||||
@na_utils.trace
|
||||
def _get_nfs_config_provisioning_options(self, specs):
|
||||
"""Return the nfs config provisioning option."""
|
||||
nfs_config = self.get_string_provisioning_options(
|
||||
specs, self.NFS_CONFIG_EXTRA_SPECS_MAP)
|
||||
|
||||
# Changes the no set config to the default value
|
||||
for k, v in nfs_config.items():
|
||||
if v is None:
|
||||
nfs_config[k] = self._default_nfs_config[k]
|
||||
|
||||
return nfs_config
|
||||
|
||||
@na_utils.trace
|
||||
def _validate_network_type(self, network_info):
|
||||
"""Raises exception if the segmentation type is incorrect."""
|
||||
@ -164,7 +208,7 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
|
||||
return self.configuration.netapp_vserver_name_template % server_id
|
||||
|
||||
@na_utils.trace
|
||||
def _create_vserver(self, vserver_name, network_info):
|
||||
def _create_vserver(self, vserver_name, network_info, nfs_config=None):
|
||||
"""Creates Vserver with given parameters if it doesn't exist."""
|
||||
|
||||
if self._client.vserver_exists(vserver_name):
|
||||
@ -205,7 +249,8 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
|
||||
network_info)
|
||||
|
||||
vserver_client.enable_nfs(
|
||||
self.configuration.netapp_enabled_share_protocols)
|
||||
self.configuration.netapp_enabled_share_protocols,
|
||||
nfs_config=nfs_config)
|
||||
|
||||
security_services = network_info.get('security_services')
|
||||
if security_services:
|
||||
@ -327,7 +372,6 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
|
||||
|
||||
if not vserver_client.network_interface_exists(
|
||||
vserver_name, node_name, port, ip_address, netmask, vlan):
|
||||
|
||||
self._client.create_network_interface(
|
||||
ip_address, netmask, vlan, node_name, port, vserver_name,
|
||||
lif_name, ipspace_name, mtu)
|
||||
@ -508,11 +552,19 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
|
||||
"""Manages a vserver by renaming it and returning backend_details."""
|
||||
new_vserver_name = self._get_vserver_name(share_server['id'])
|
||||
old_vserver_name = self._get_correct_vserver_old_name(identifier)
|
||||
|
||||
if new_vserver_name != old_vserver_name:
|
||||
self._client.rename_vserver(old_vserver_name, new_vserver_name)
|
||||
|
||||
backend_details = {'vserver_name': new_vserver_name}
|
||||
backend_details = {
|
||||
'vserver_name': new_vserver_name,
|
||||
}
|
||||
|
||||
if self.is_nfs_config_supported:
|
||||
nfs_config = self._client.get_nfs_config(
|
||||
list(self.NFS_CONFIG_EXTRA_SPECS_MAP.values()),
|
||||
new_vserver_name)
|
||||
backend_details['nfs_config'] = jsonutils.dumps(nfs_config)
|
||||
|
||||
return new_vserver_name, backend_details
|
||||
|
||||
def unmanage_server(self, server_details, security_services=None):
|
||||
@ -607,5 +659,143 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
|
||||
|
||||
return (super(NetAppCmodeMultiSVMFileStorageLibrary, self)
|
||||
.create_share_from_snapshot(
|
||||
context, share, snapshot, share_server=share_server,
|
||||
parent_share=parent_share))
|
||||
context, share, snapshot, share_server=share_server,
|
||||
parent_share=parent_share))
|
||||
|
||||
@na_utils.trace
|
||||
def _is_share_server_compatible(self, share_server, expected_nfs_config):
|
||||
"""Check if the share server has the given nfs config
|
||||
|
||||
The None and the default_nfs_config should be considered
|
||||
as the same configuration.
|
||||
"""
|
||||
nfs_config = share_server.get('backend_details', {}).get('nfs_config')
|
||||
share_server_nfs = jsonutils.loads(nfs_config) if nfs_config else None
|
||||
|
||||
if share_server_nfs == expected_nfs_config:
|
||||
return True
|
||||
elif (share_server_nfs is None and
|
||||
expected_nfs_config == self._default_nfs_config):
|
||||
return True
|
||||
elif (expected_nfs_config is None and
|
||||
share_server_nfs == self._default_nfs_config):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def choose_share_server_compatible_with_share(self, context, share_servers,
|
||||
share, snapshot=None,
|
||||
share_group=None):
|
||||
"""Method that allows driver to choose share server for provided share.
|
||||
|
||||
If compatible share-server is not found, method should return None.
|
||||
|
||||
:param context: Current context
|
||||
:param share_servers: list with share-server models
|
||||
:param share: share model
|
||||
:param snapshot: snapshot model
|
||||
:param share_group: ShareGroup model with shares
|
||||
:returns: share-server or None
|
||||
"""
|
||||
if not share_servers:
|
||||
# No share server to reuse
|
||||
return None
|
||||
|
||||
nfs_config = None
|
||||
if self.is_nfs_config_supported:
|
||||
extra_specs = share_types.get_extra_specs_from_share(share)
|
||||
nfs_config = self._get_nfs_config_provisioning_options(extra_specs)
|
||||
|
||||
for share_server in share_servers:
|
||||
if self._check_reuse_share_server(share_server, nfs_config,
|
||||
share_group=share_group):
|
||||
return share_server
|
||||
return None
|
||||
|
||||
@na_utils.trace
|
||||
def _check_reuse_share_server(self, share_server, nfs_config,
|
||||
share_group=None):
|
||||
"""Check whether the share_server can be reused or not."""
|
||||
if (share_group and share_group.get('share_server_id') !=
|
||||
share_server['id']):
|
||||
return False
|
||||
|
||||
if self.is_nfs_config_supported:
|
||||
# NOTE(felipe_rodrigues): Do not check that the share nfs_config
|
||||
# matches with the group nfs_config, because the API guarantees
|
||||
# that the share type is an element of the group types.
|
||||
return self._is_share_server_compatible(share_server, nfs_config)
|
||||
|
||||
return True
|
||||
|
||||
@na_utils.trace
|
||||
def choose_share_server_compatible_with_share_group(
|
||||
self, context, share_servers, share_group_ref,
|
||||
share_group_snapshot=None):
|
||||
"""Choose the server compatible with group.
|
||||
|
||||
If the NFS configuration is supported, it will check that the group
|
||||
types agree for the NFS extra-specs values.
|
||||
"""
|
||||
if not share_servers:
|
||||
# No share server to reuse
|
||||
return None
|
||||
|
||||
nfs_config = None
|
||||
if self.is_nfs_config_supported:
|
||||
nfs_config = self._get_nfs_config_share_group(share_group_ref)
|
||||
|
||||
for share_server in share_servers:
|
||||
if self._check_reuse_share_server(share_server, nfs_config):
|
||||
return share_server
|
||||
|
||||
return None
|
||||
|
||||
@na_utils.trace
|
||||
def _get_nfs_config_share_group(self, share_group_ref):
|
||||
"""Get the NFS config of the share group.
|
||||
|
||||
In case the group types do not agree for the NFS config, it throws an
|
||||
exception.
|
||||
"""
|
||||
nfs_config = None
|
||||
first = True
|
||||
for st in share_group_ref.get('share_types', []):
|
||||
extra_specs = share_types.get_share_type_extra_specs(
|
||||
st['share_type_id'])
|
||||
|
||||
if first:
|
||||
self._check_nfs_config_extra_specs_validity(extra_specs)
|
||||
nfs_config = self._get_nfs_config_provisioning_options(
|
||||
extra_specs)
|
||||
first = False
|
||||
continue
|
||||
|
||||
type_nfs_config = self._get_nfs_config_provisioning_options(
|
||||
extra_specs)
|
||||
if nfs_config != type_nfs_config:
|
||||
msg = _("The specified share_types cannot have "
|
||||
"conflicting values for the NFS configuration "
|
||||
"extra-specs.")
|
||||
raise exception.InvalidInput(reason=msg)
|
||||
|
||||
return nfs_config
|
||||
|
||||
@na_utils.trace
|
||||
def manage_existing(self, share, driver_options, share_server=None):
|
||||
|
||||
# In case NFS config is supported, the share's nfs_config must be the
|
||||
# same as the server
|
||||
if share_server and self.is_nfs_config_supported:
|
||||
extra_specs = share_types.get_extra_specs_from_share(share)
|
||||
nfs_config = self._get_nfs_config_provisioning_options(extra_specs)
|
||||
if not self._is_share_server_compatible(share_server, nfs_config):
|
||||
args = {'server_id': share_server['id']}
|
||||
msg = _('Invalid NFS configuration for the server '
|
||||
'%(server_id)s . The extra-specs must match the '
|
||||
'values of NFS of the server.')
|
||||
raise exception.NetAppException(msg % args)
|
||||
|
||||
return (super(NetAppCmodeMultiSVMFileStorageLibrary, self).
|
||||
manage_existing(share, driver_options,
|
||||
share_server=share_server))
|
||||
|
@ -2409,6 +2409,43 @@ VOLUME_MOVE_GET_ITER_RESULT = etree.XML("""
|
||||
'vserver': VSERVER_NAME,
|
||||
})
|
||||
|
||||
NFS_INFO_STR = """
|
||||
<nfs-info>
|
||||
<is-rquota-enabled>false</is-rquota-enabled>
|
||||
<is-tcp-enabled>true</is-tcp-enabled>
|
||||
<is-v3-hide-snapshot>false</is-v3-hide-snapshot>
|
||||
<ntfs-unix-security-ops>use_export_policy</ntfs-unix-security-ops>
|
||||
<permitted-enc-types>
|
||||
<string>des</string>
|
||||
<string>des3</string>
|
||||
<string>aes_128</string>
|
||||
<string>aes_256</string>
|
||||
</permitted-enc-types>
|
||||
<tcp-max-xfer-size>65536</tcp-max-xfer-size>
|
||||
<udp-max-xfer-size>32768</udp-max-xfer-size>
|
||||
<v3-search-unconverted-filename>false</v3-search-unconverted-filename>
|
||||
<v4-inherited-acl-preserve>false</v4-inherited-acl-preserve>
|
||||
</nfs-info>
|
||||
"""
|
||||
|
||||
NFS_INFO_DEFAULT_TREE = etree.XML(NFS_INFO_STR)
|
||||
|
||||
NFS_CONFIG_DEFAULT_RESULT = etree.XML("""
|
||||
<results status="passed">
|
||||
<defaults>
|
||||
%s
|
||||
</defaults>
|
||||
</results>
|
||||
""" % NFS_INFO_STR)
|
||||
|
||||
NFS_CONFIG_SERVER_RESULT = etree.XML("""
|
||||
<results status="passed">
|
||||
<attributes-list>
|
||||
%s
|
||||
</attributes-list>
|
||||
</results>
|
||||
""" % NFS_INFO_STR)
|
||||
|
||||
PERF_OBJECT_COUNTER_TOTAL_CP_MSECS_LABELS = [
|
||||
'SETUP', 'PRE_P0', 'P0_SNAP_DEL', 'P1_CLEAN', 'P1_QUOTA', 'IPU_DISK_ADD',
|
||||
'P2V_INOFILE', 'P2V_INO_PUB', 'P2V_INO_PRI', 'P2V_FSINFO', 'P2V_DLOG1',
|
||||
|
@ -2398,18 +2398,24 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
||||
self.client.send_request.assert_has_calls([
|
||||
mock.call('vserver-modify', vserver_modify_args)])
|
||||
|
||||
def test_enable_nfs(self):
|
||||
@ddt.data({'tcp-max-xfer-size': 10000}, {}, None)
|
||||
def test_enable_nfs(self, nfs_config):
|
||||
|
||||
self.mock_object(self.client, 'send_request')
|
||||
self.mock_object(self.client, '_enable_nfs_protocols')
|
||||
self.mock_object(self.client, '_create_default_nfs_export_rules')
|
||||
self.mock_object(self.client, '_configure_nfs')
|
||||
|
||||
self.client.enable_nfs(fake.NFS_VERSIONS)
|
||||
self.client.enable_nfs(fake.NFS_VERSIONS, nfs_config)
|
||||
|
||||
self.client.send_request.assert_called_once_with('nfs-enable')
|
||||
self.client._enable_nfs_protocols.assert_called_once_with(
|
||||
fake.NFS_VERSIONS)
|
||||
self.client._create_default_nfs_export_rules.assert_called_once_with()
|
||||
if nfs_config:
|
||||
self.client._configure_nfs.assert_called_once_with(nfs_config)
|
||||
else:
|
||||
self.client._configure_nfs.assert_not_called()
|
||||
|
||||
@ddt.data((True, True, True), (True, False, False), (False, True, True))
|
||||
@ddt.unpack
|
||||
@ -2435,6 +2441,17 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
||||
self.client.send_request.assert_called_once_with(
|
||||
'nfs-service-modify', nfs_service_modify_args)
|
||||
|
||||
def test_configure_nfs(self):
|
||||
fake_nfs = {
|
||||
'tcp-max-xfer-size': 10000,
|
||||
}
|
||||
self.mock_object(self.client, 'send_request')
|
||||
|
||||
self.client._configure_nfs(fake_nfs)
|
||||
|
||||
self.client.send_request.assert_called_once_with(
|
||||
'nfs-service-modify', fake_nfs)
|
||||
|
||||
def test_create_default_nfs_export_rules(self):
|
||||
|
||||
class CopyingMock(mock.Mock):
|
||||
@ -6790,3 +6807,74 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
||||
self.client.send_iter_request.assert_called_once_with(
|
||||
'volume-get-iter', expected_api_args)
|
||||
self.assertEqual(expected_snapshot_name, result)
|
||||
|
||||
def test_get_nfs_config(self):
|
||||
api_args = {
|
||||
'query': {
|
||||
'nfs-info': {
|
||||
'vserver': 'vserver',
|
||||
},
|
||||
},
|
||||
'desired-attributes': {
|
||||
'nfs-info': {
|
||||
'field': None,
|
||||
},
|
||||
},
|
||||
}
|
||||
api_response = netapp_api.NaElement(
|
||||
fake.NFS_CONFIG_SERVER_RESULT)
|
||||
self.mock_object(self.client,
|
||||
'send_request',
|
||||
mock.Mock(return_value=api_response))
|
||||
self.mock_object(self.client,
|
||||
'parse_nfs_config',
|
||||
mock.Mock(return_value=None))
|
||||
|
||||
self.client.get_nfs_config(['field'], 'vserver')
|
||||
|
||||
self.client.send_request.assert_called_once_with(
|
||||
'nfs-service-get-iter', api_args)
|
||||
|
||||
def test_get_nfs_config_default(self):
|
||||
api_response = netapp_api.NaElement(
|
||||
fake.NFS_CONFIG_DEFAULT_RESULT)
|
||||
self.mock_object(self.client,
|
||||
'send_request',
|
||||
mock.Mock(return_value=api_response))
|
||||
self.mock_object(self.client,
|
||||
'parse_nfs_config',
|
||||
mock.Mock(return_value=None))
|
||||
|
||||
self.client.get_nfs_config_default(['field'])
|
||||
|
||||
self.client.send_request.assert_called_once_with(
|
||||
'nfs-service-get-create-defaults', None)
|
||||
|
||||
@ddt.data(
|
||||
{'nfs_info': fake.NFS_CONFIG_SERVER_RESULT,
|
||||
'desired_args': ['tcp-max-xfer-size'],
|
||||
'expected_nfs': {
|
||||
'tcp-max-xfer-size': '65536',
|
||||
}},
|
||||
{'nfs_info': fake.NFS_CONFIG_SERVER_RESULT,
|
||||
'desired_args': ['udp-max-xfer-size'],
|
||||
'expected_nfs': {
|
||||
'udp-max-xfer-size': '32768',
|
||||
}},
|
||||
{'nfs_info': fake.NFS_CONFIG_SERVER_RESULT,
|
||||
'desired_args': ['tcp-max-xfer-size', 'udp-max-xfer-size'],
|
||||
'expected_nfs': {
|
||||
'tcp-max-xfer-size': '65536',
|
||||
'udp-max-xfer-size': '32768',
|
||||
}},
|
||||
{'nfs_info': fake.NFS_CONFIG_SERVER_RESULT,
|
||||
'desired_args': [],
|
||||
'expected_nfs': {}})
|
||||
@ddt.unpack
|
||||
def test_parse_nfs_config(self, nfs_info, desired_args, expected_nfs):
|
||||
parent_elem = netapp_api.NaElement(nfs_info).get_child_by_name(
|
||||
'attributes-list')
|
||||
|
||||
nfs_config = self.client.parse_nfs_config(parent_elem, desired_args)
|
||||
|
||||
self.assertDictEqual(nfs_config, expected_nfs)
|
||||
|
@ -118,6 +118,9 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
self.mock_object(
|
||||
self.library._client, 'check_for_cluster_credentials',
|
||||
mock.Mock(return_value=True))
|
||||
self.mock_object(
|
||||
self.library._client, 'get_nfs_config_default',
|
||||
mock.Mock(return_value=fake.NFS_CONFIG_DEFAULT))
|
||||
self.mock_object(
|
||||
self.library, '_check_snaprestore_license',
|
||||
mock.Mock(return_value=True))
|
||||
@ -125,12 +128,17 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
self.library,
|
||||
'_get_licenses',
|
||||
mock.Mock(return_value=fake.LICENSES))
|
||||
mock_get_api_client.features.TRANSFER_LIMIT_NFS_CONFIG = True
|
||||
|
||||
self.library.do_setup(self.context)
|
||||
|
||||
self.assertEqual(fake.LICENSES, self.library._licenses)
|
||||
mock_get_api_client.assert_called_once_with()
|
||||
(self.library._client.check_for_cluster_credentials.
|
||||
assert_called_once_with())
|
||||
(self.library._client.get_nfs_config_default.
|
||||
assert_called_once_with(
|
||||
list(self.library.NFS_CONFIG_EXTRA_SPECS_MAP.values())))
|
||||
self.assertEqual('fake_perf_library', self.library._perf_library)
|
||||
self.mock_object(self.library._client,
|
||||
'check_for_cluster_credentials',
|
||||
@ -1481,14 +1489,14 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_get_string_provisioning_options(self):
|
||||
result = self.library._get_string_provisioning_options(
|
||||
result = self.library.get_string_provisioning_options(
|
||||
fake.STRING_EXTRA_SPEC,
|
||||
self.library.STRING_QUALIFIED_EXTRA_SPECS_MAP)
|
||||
|
||||
self.assertEqual(fake.PROVISIONING_OPTIONS_STRING, result)
|
||||
|
||||
def test_get_string_provisioning_options_missing_spec(self):
|
||||
result = self.library._get_string_provisioning_options(
|
||||
result = self.library.get_string_provisioning_options(
|
||||
fake.SHORT_STRING_EXTRA_SPEC,
|
||||
self.library.STRING_QUALIFIED_EXTRA_SPECS_MAP)
|
||||
|
||||
@ -1496,7 +1504,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
result)
|
||||
|
||||
def test_get_string_provisioning_options_implicit_false(self):
|
||||
result = self.library._get_string_provisioning_options(
|
||||
result = self.library.get_string_provisioning_options(
|
||||
fake.EMPTY_EXTRA_SPEC,
|
||||
self.library.STRING_QUALIFIED_EXTRA_SPECS_MAP)
|
||||
|
||||
|
@ -30,6 +30,7 @@ from manila.share.drivers.netapp.dataontap.cluster_mode import data_motion
|
||||
from manila.share.drivers.netapp.dataontap.cluster_mode import lib_base
|
||||
from manila.share.drivers.netapp.dataontap.cluster_mode import lib_multi_svm
|
||||
from manila.share.drivers.netapp import utils as na_utils
|
||||
from manila.share import share_types
|
||||
from manila.share import utils as share_utils
|
||||
from manila import test
|
||||
from manila.tests.share.drivers.netapp.dataontap.client import fakes as c_fake
|
||||
@ -84,6 +85,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
|
||||
self.fake_new_client = mock.Mock()
|
||||
self.fake_client = mock.Mock()
|
||||
self.library._default_nfs_config = fake.NFS_CONFIG_DEFAULT
|
||||
|
||||
def test_check_for_setup_error_cluster_creds_no_vserver(self):
|
||||
self.library._have_cluster_creds = True
|
||||
@ -229,8 +231,11 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
}
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
@ddt.data('fake', fake.IDENTIFIER)
|
||||
def test_manage_server(self, fake_vserver_name):
|
||||
@ddt.data({'fake_vserver_name': fake, 'nfs_config_support': False},
|
||||
{'fake_vserver_name': fake.IDENTIFIER,
|
||||
'nfs_config_support': True})
|
||||
@ddt.unpack
|
||||
def test_manage_server(self, fake_vserver_name, nfs_config_support):
|
||||
|
||||
self.mock_object(context,
|
||||
'get_admin_context',
|
||||
@ -238,6 +243,10 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
mock_get_vserver_name = self.mock_object(
|
||||
self.library, '_get_vserver_name',
|
||||
mock.Mock(return_value=fake_vserver_name))
|
||||
self.library.is_nfs_config_supported = nfs_config_support
|
||||
mock_get_nfs_config = self.mock_object(
|
||||
self.library._client, 'get_nfs_config',
|
||||
mock.Mock(return_value=fake.NFS_CONFIG_DEFAULT))
|
||||
|
||||
new_identifier, new_details = self.library.manage_server(
|
||||
context, fake.SHARE_SERVER, fake.IDENTIFIER, {})
|
||||
@ -245,6 +254,14 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
mock_get_vserver_name.assert_called_once_with(fake.SHARE_SERVER['id'])
|
||||
self.assertEqual(fake_vserver_name, new_details['vserver_name'])
|
||||
self.assertEqual(fake_vserver_name, new_identifier)
|
||||
if nfs_config_support:
|
||||
mock_get_nfs_config.assert_called_once_with(
|
||||
list(self.library.NFS_CONFIG_EXTRA_SPECS_MAP.values()),
|
||||
fake_vserver_name)
|
||||
self.assertEqual(jsonutils.dumps(fake.NFS_CONFIG_DEFAULT),
|
||||
new_details['nfs_config'])
|
||||
else:
|
||||
mock_get_nfs_config.assert_not_called()
|
||||
|
||||
def test_get_share_server_network_info(self):
|
||||
|
||||
@ -318,20 +335,37 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
self.assertListEqual([fake.AGGREGATES[0]], result)
|
||||
mock_list_non_root_aggregates.assert_called_once_with()
|
||||
|
||||
def test_setup_server(self):
|
||||
|
||||
@ddt.data({'nfs_config_support': False},
|
||||
{'nfs_config_support': True,
|
||||
'nfs_config': fake.NFS_CONFIG_UDP_MAX},
|
||||
{'nfs_config_support': True,
|
||||
'nfs_config': fake.NFS_CONFIG_DEFAULT})
|
||||
@ddt.unpack
|
||||
def test_setup_server(self, nfs_config_support, nfs_config=None):
|
||||
mock_get_vserver_name = self.mock_object(
|
||||
self.library,
|
||||
'_get_vserver_name',
|
||||
mock.Mock(return_value=fake.VSERVER1))
|
||||
|
||||
mock_create_vserver = self.mock_object(self.library, '_create_vserver')
|
||||
|
||||
mock_validate_network_type = self.mock_object(
|
||||
self.library,
|
||||
'_validate_network_type')
|
||||
self.library.is_nfs_config_supported = nfs_config_support
|
||||
mock_get_extra_spec = self.mock_object(
|
||||
share_types, "get_share_type_extra_specs",
|
||||
mock.Mock(return_value=fake.EXTRA_SPEC))
|
||||
mock_check_extra_spec = self.mock_object(
|
||||
self.library,
|
||||
'_check_nfs_config_extra_specs_validity',
|
||||
mock.Mock())
|
||||
mock_get_nfs_config = self.mock_object(
|
||||
self.library,
|
||||
"_get_nfs_config_provisioning_options",
|
||||
mock.Mock(return_value=nfs_config))
|
||||
|
||||
result = self.library.setup_server(fake.NETWORK_INFO)
|
||||
result = self.library.setup_server(fake.NETWORK_INFO,
|
||||
fake.SERVER_METADATA)
|
||||
|
||||
ports = {}
|
||||
for network_allocation in fake.NETWORK_INFO['network_allocations']:
|
||||
@ -340,11 +374,28 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
self.assertTrue(mock_validate_network_type.called)
|
||||
self.assertTrue(mock_get_vserver_name.called)
|
||||
self.assertTrue(mock_create_vserver.called)
|
||||
self.assertDictEqual({'vserver_name': fake.VSERVER1,
|
||||
'ports': jsonutils.dumps(ports)}, result)
|
||||
if nfs_config_support:
|
||||
mock_get_extra_spec.assert_called_once_with(
|
||||
fake.SERVER_METADATA['share_type_id'])
|
||||
mock_check_extra_spec.assert_called_once_with(
|
||||
fake.EXTRA_SPEC)
|
||||
mock_get_nfs_config.assert_called_once_with(
|
||||
fake.EXTRA_SPEC)
|
||||
else:
|
||||
mock_get_extra_spec.assert_not_called()
|
||||
mock_check_extra_spec.assert_not_called()
|
||||
mock_get_nfs_config.assert_not_called()
|
||||
|
||||
expected = {
|
||||
'vserver_name': fake.VSERVER1,
|
||||
'ports': jsonutils.dumps(ports),
|
||||
}
|
||||
if nfs_config_support:
|
||||
expected.update({'nfs_config': jsonutils.dumps(nfs_config)})
|
||||
self.assertDictEqual(expected, result)
|
||||
|
||||
def test_setup_server_with_error(self):
|
||||
|
||||
self.library.is_nfs_config_supported = False
|
||||
mock_get_vserver_name = self.mock_object(
|
||||
self.library,
|
||||
'_get_vserver_name',
|
||||
@ -363,7 +414,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
self.assertRaises(
|
||||
exception.ManilaException,
|
||||
self.library.setup_server,
|
||||
fake.NETWORK_INFO)
|
||||
fake.NETWORK_INFO,
|
||||
fake.SERVER_METADATA)
|
||||
|
||||
ports = {}
|
||||
for network_allocation in fake.NETWORK_INFO['network_allocations']:
|
||||
@ -372,9 +424,12 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
self.assertTrue(mock_validate_network_type.called)
|
||||
self.assertTrue(mock_get_vserver_name.called)
|
||||
self.assertTrue(mock_create_vserver.called)
|
||||
|
||||
self.assertDictEqual(
|
||||
{'server_details': {'vserver_name': fake.VSERVER1,
|
||||
'ports': jsonutils.dumps(ports)}},
|
||||
{'server_details': {
|
||||
'vserver_name': fake.VSERVER1,
|
||||
'ports': jsonutils.dumps(ports),
|
||||
}},
|
||||
fake_exception.detail_data)
|
||||
|
||||
@ddt.data(
|
||||
@ -442,7 +497,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
self.mock_object(self.library, '_create_vserver_admin_lif')
|
||||
self.mock_object(self.library, '_create_vserver_routes')
|
||||
|
||||
self.library._create_vserver(vserver_name, fake.NETWORK_INFO)
|
||||
self.library._create_vserver(vserver_name, fake.NETWORK_INFO,
|
||||
fake.NFS_CONFIG_TCP_UDP_MAX)
|
||||
|
||||
get_ipspace_name_for_vlan_port.assert_called_once_with(
|
||||
fake.CLUSTER_NODES[0],
|
||||
@ -462,7 +518,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
vserver_name, vserver_client, fake.NETWORK_INFO, fake.IPSPACE)
|
||||
self.library._create_vserver_routes.assert_called_once_with(
|
||||
vserver_client, fake.NETWORK_INFO)
|
||||
vserver_client.enable_nfs.assert_called_once_with(versions)
|
||||
vserver_client.enable_nfs.assert_called_once_with(
|
||||
versions, nfs_config=fake.NFS_CONFIG_TCP_UDP_MAX)
|
||||
self.library._client.setup_security_services.assert_called_once_with(
|
||||
fake.NETWORK_INFO['security_services'], vserver_client,
|
||||
vserver_name)
|
||||
@ -482,7 +539,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
self.assertRaises(exception.NetAppException,
|
||||
self.library._create_vserver,
|
||||
vserver_name,
|
||||
fake.NETWORK_INFO)
|
||||
fake.NETWORK_INFO,
|
||||
fake.NFS_CONFIG_TCP_UDP_MAX)
|
||||
|
||||
@ddt.data(
|
||||
{'lif_exception': netapp_api.NaApiError,
|
||||
@ -534,7 +592,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
self.assertRaises(lif_exception,
|
||||
self.library._create_vserver,
|
||||
vserver_name,
|
||||
fake.NETWORK_INFO)
|
||||
fake.NETWORK_INFO,
|
||||
fake.NFS_CONFIG_TCP_UDP_MAX)
|
||||
|
||||
self.library._get_api_client.assert_called_with(vserver=vserver_name)
|
||||
self.assertTrue(self.library._client.create_vserver.called)
|
||||
@ -1213,3 +1272,360 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
mock_create_from_snap.assert_called_once_with(
|
||||
None, fake.SHARE, fake.SNAPSHOT, share_server=fake.SHARE_SERVER,
|
||||
parent_share=fake_parent_share)
|
||||
|
||||
def test_check_if_extra_spec_is_positive_with_negative_integer(self):
|
||||
self.assertRaises(exception.NetAppException,
|
||||
self.library._check_if_max_files_is_valid,
|
||||
fake.SHARE, -1)
|
||||
|
||||
def test_check_if_extra_spec_is_positive_with_string(self):
|
||||
self.assertRaises(ValueError,
|
||||
self.library._check_if_max_files_is_valid,
|
||||
fake.SHARE, 'abc')
|
||||
|
||||
def test_check_nfs_config_extra_specs_validity(self):
|
||||
result = self.library._check_nfs_config_extra_specs_validity(
|
||||
fake.EXTRA_SPEC)
|
||||
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_check_nfs_config_extra_specs_validity_empty_spec(self):
|
||||
result = self.library._check_nfs_config_extra_specs_validity({})
|
||||
|
||||
self.assertIsNone(result)
|
||||
|
||||
@ddt.data(fake.INVALID_TCP_MAX_XFER_SIZE_EXTRA_SPEC,
|
||||
fake.INVALID_UDP_MAX_XFER_SIZE_EXTRA_SPEC)
|
||||
def test_check_nfs_config_extra_specs_validity_invalid_value(self,
|
||||
extra_specs):
|
||||
self.assertRaises(
|
||||
exception.NetAppException,
|
||||
self.library._check_nfs_config_extra_specs_validity,
|
||||
extra_specs)
|
||||
|
||||
@ddt.data({}, fake.STRING_EXTRA_SPEC)
|
||||
def test_get_nfs_config_provisioning_options_empty(self, extra_specs):
|
||||
result = self.library._get_nfs_config_provisioning_options(
|
||||
extra_specs)
|
||||
|
||||
self.assertDictEqual(result, fake.NFS_CONFIG_DEFAULT)
|
||||
|
||||
@ddt.data(
|
||||
{'extra_specs': fake.NFS_CONFIG_TCP_MAX_DDT['extra_specs'],
|
||||
'expected': fake.NFS_CONFIG_TCP_MAX_DDT['expected']},
|
||||
{'extra_specs': fake.NFS_CONFIG_UDP_MAX_DDT['extra_specs'],
|
||||
'expected': fake.NFS_CONFIG_UDP_MAX_DDT['expected']},
|
||||
{'extra_specs': fake.NFS_CONFIG_TCP_UDP_MAX_DDT['extra_specs'],
|
||||
'expected': fake.NFS_CONFIG_TCP_UDP_MAX_DDT['expected']},
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_get_nfs_config_provisioning_options_valid(self, extra_specs,
|
||||
expected):
|
||||
result = self.library._get_nfs_config_provisioning_options(
|
||||
extra_specs)
|
||||
|
||||
self.assertDictEqual(expected, result)
|
||||
|
||||
@ddt.data({'fake_share_server': fake.SHARE_SERVER_NFS_TCP,
|
||||
'expected_nfs_config': fake.NFS_CONFIG_TCP_MAX},
|
||||
{'fake_share_server': fake.SHARE_SERVER_NFS_UDP,
|
||||
'expected_nfs_config': fake.NFS_CONFIG_UDP_MAX},
|
||||
{'fake_share_server': fake.SHARE_SERVER_NFS_TCP_UDP,
|
||||
'expected_nfs_config': fake.NFS_CONFIG_TCP_UDP_MAX},
|
||||
{'fake_share_server': fake.SHARE_SERVER_NO_DETAILS,
|
||||
'expected_nfs_config': fake.NFS_CONFIG_DEFAULT},
|
||||
{'fake_share_server': fake.SHARE_SERVER_NFS_DEFAULT,
|
||||
'expected_nfs_config': None},
|
||||
{'fake_share_server': fake.SHARE_SERVER_NO_NFS_NONE,
|
||||
'expected_nfs_config': fake.NFS_CONFIG_DEFAULT})
|
||||
@ddt.unpack
|
||||
def test_is_share_server_compatible_true(self, fake_share_server,
|
||||
expected_nfs_config):
|
||||
is_same = self.library._is_share_server_compatible(
|
||||
fake_share_server, expected_nfs_config)
|
||||
self.assertTrue(is_same)
|
||||
|
||||
@ddt.data({'fake_share_server': fake.SHARE_SERVER_NFS_TCP,
|
||||
'expected_nfs_config': fake.NFS_CONFIG_UDP_MAX},
|
||||
{'fake_share_server': fake.SHARE_SERVER_NFS_UDP,
|
||||
'expected_nfs_config': fake.NFS_CONFIG_TCP_MAX},
|
||||
{'fake_share_server': fake.SHARE_SERVER_NFS_TCP_UDP,
|
||||
'expected_nfs_config': fake.NFS_CONFIG_TCP_MAX},
|
||||
{'fake_share_server': fake.SHARE_SERVER_NFS_TCP_UDP,
|
||||
'expected_nfs_config': fake.NFS_CONFIG_UDP_MAX},
|
||||
{'fake_share_server': fake.SHARE_SERVER_NFS_TCP_UDP,
|
||||
'expected_nfs_config': None},
|
||||
{'fake_share_server': fake.SHARE_SERVER_NFS_TCP_UDP,
|
||||
'expected_nfs_config': {}},
|
||||
{'fake_share_server': fake.SHARE_SERVER_NFS_TCP_UDP,
|
||||
'expected_nfs_config': fake.NFS_CONFIG_DEFAULT},
|
||||
{'fake_share_server': fake.SHARE_SERVER_NO_DETAILS,
|
||||
'expected_nfs_config': fake.NFS_CONFIG_UDP_MAX},
|
||||
{'fake_share_server': fake.SHARE_SERVER_NFS_DEFAULT,
|
||||
'expected_nfs_config': fake.NFS_CONFIG_UDP_MAX},
|
||||
{'fake_share_server': fake.SHARE_SERVER_NO_NFS_NONE,
|
||||
'expected_nfs_config': fake.NFS_CONFIG_TCP_MAX})
|
||||
@ddt.unpack
|
||||
def test_is_share_server_compatible_false(self, fake_share_server,
|
||||
expected_nfs_config):
|
||||
is_same = self.library._is_share_server_compatible(
|
||||
fake_share_server, expected_nfs_config)
|
||||
self.assertFalse(is_same)
|
||||
|
||||
@ddt.data(
|
||||
{'expected_server': fake.SHARE_SERVER_NFS_TCP,
|
||||
'share_group': {'share_server_id': fake.SHARE_SERVER_NFS_TCP['id']},
|
||||
'nfs_config': fake.NFS_CONFIG_TCP_MAX},
|
||||
{'expected_server': fake.SHARE_SERVER_NFS_UDP,
|
||||
'share_group': {'share_server_id': fake.SHARE_SERVER_NFS_UDP['id']},
|
||||
'nfs_config': fake.NFS_CONFIG_UDP_MAX},
|
||||
{'expected_server': fake.SHARE_SERVER_NFS_TCP_UDP,
|
||||
'share_group': {
|
||||
'share_server_id': fake.SHARE_SERVER_NFS_TCP_UDP['id']},
|
||||
'nfs_config': fake.NFS_CONFIG_TCP_UDP_MAX},
|
||||
{'expected_server': fake.SHARE_SERVER_NFS_DEFAULT,
|
||||
'share_group': {
|
||||
'share_server_id': fake.SHARE_SERVER_NFS_DEFAULT['id']},
|
||||
'nfs_config': fake.NFS_CONFIG_DEFAULT},
|
||||
{'expected_server': None,
|
||||
'share_group': {'share_server_id': 'invalid_id'},
|
||||
'nfs_config': fake.NFS_CONFIG_TCP_MAX})
|
||||
@ddt.unpack
|
||||
def test_choose_share_server_compatible_with_share_group_and_nfs_config(
|
||||
self, expected_server, share_group, nfs_config):
|
||||
self.library.is_nfs_config_supported = True
|
||||
mock_get_extra_spec = self.mock_object(
|
||||
share_types, "get_extra_specs_from_share",
|
||||
mock.Mock(return_value=fake.EXTRA_SPEC))
|
||||
mock_get_nfs_config = self.mock_object(
|
||||
self.library,
|
||||
"_get_nfs_config_provisioning_options",
|
||||
mock.Mock(return_value=nfs_config))
|
||||
|
||||
server = self.library.choose_share_server_compatible_with_share(
|
||||
None, fake.SHARE_SERVERS, fake.SHARE, None, share_group)
|
||||
|
||||
mock_get_extra_spec.assert_called_once_with(fake.SHARE)
|
||||
mock_get_nfs_config.assert_called_once_with(fake.EXTRA_SPEC)
|
||||
self.assertEqual(expected_server, server)
|
||||
|
||||
@ddt.data(
|
||||
{'expected_server': fake.SHARE_SERVER_NO_NFS_NONE,
|
||||
'share_group': {'share_server_id':
|
||||
fake.SHARE_SERVER_NO_NFS_NONE['id']}},
|
||||
{'expected_server': fake.SHARE_SERVER_NO_DETAILS,
|
||||
'share_group': {'share_server_id':
|
||||
fake.SHARE_SERVER_NO_DETAILS['id']}},
|
||||
{'expected_server': fake.SHARE_SERVER_NO_DETAILS,
|
||||
'share_group': {
|
||||
'share_server_id': fake.SHARE_SERVER_NO_DETAILS['id']},
|
||||
'nfs_config_support': False},
|
||||
{'expected_server': None,
|
||||
'share_group': {'share_server_id': 'invalid_id'}})
|
||||
@ddt.unpack
|
||||
def test_choose_share_server_compatible_with_share_group_only(
|
||||
self, expected_server, share_group, nfs_config_support=True):
|
||||
self.library.is_nfs_config_supported = nfs_config_support
|
||||
mock_get_extra_spec = self.mock_object(
|
||||
share_types, "get_extra_specs_from_share",
|
||||
mock.Mock(return_value=fake.EMPTY_EXTRA_SPEC))
|
||||
mock_get_nfs_config = self.mock_object(
|
||||
self.library,
|
||||
"_get_nfs_config_provisioning_options",
|
||||
mock.Mock(return_value=fake.NFS_CONFIG_DEFAULT))
|
||||
|
||||
server = self.library.choose_share_server_compatible_with_share(
|
||||
None, fake.SHARE_SERVERS, fake.SHARE, None, share_group)
|
||||
|
||||
self.assertEqual(expected_server, server)
|
||||
if nfs_config_support:
|
||||
mock_get_extra_spec.assert_called_once_with(fake.SHARE)
|
||||
mock_get_nfs_config.assert_called_once_with(fake.EMPTY_EXTRA_SPEC)
|
||||
|
||||
@ddt.data(
|
||||
{'expected_server': fake.SHARE_SERVER_NFS_TCP,
|
||||
'nfs_config': fake.NFS_CONFIG_TCP_MAX},
|
||||
{'expected_server': fake.SHARE_SERVER_NFS_UDP,
|
||||
'nfs_config': fake.NFS_CONFIG_UDP_MAX},
|
||||
{'expected_server': fake.SHARE_SERVER_NFS_TCP_UDP,
|
||||
'nfs_config': fake.NFS_CONFIG_TCP_UDP_MAX},
|
||||
{'expected_server': fake.SHARE_SERVER_NFS_DEFAULT,
|
||||
'nfs_config': fake.NFS_CONFIG_DEFAULT},
|
||||
{'expected_server': None,
|
||||
'nfs_config': {'invalid': 'invalid'}},
|
||||
{'expected_server': fake.SHARE_SERVER_NFS_TCP,
|
||||
'nfs_config': None, 'nfs_config_support': False},
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_choose_share_server_compatible_with_share_nfs_config_only(
|
||||
self, expected_server, nfs_config, nfs_config_support=True):
|
||||
self.library.is_nfs_config_supported = nfs_config_support
|
||||
mock_get_extra_spec = self.mock_object(
|
||||
share_types, "get_extra_specs_from_share",
|
||||
mock.Mock(return_value=fake.EXTRA_SPEC))
|
||||
mock_get_nfs_config = self.mock_object(
|
||||
self.library,
|
||||
"_get_nfs_config_provisioning_options",
|
||||
mock.Mock(return_value=nfs_config))
|
||||
|
||||
server = self.library.choose_share_server_compatible_with_share(
|
||||
None, fake.SHARE_SERVERS, fake.SHARE)
|
||||
|
||||
self.assertEqual(expected_server, server)
|
||||
if nfs_config_support:
|
||||
mock_get_extra_spec.assert_called_once_with(fake.SHARE)
|
||||
mock_get_nfs_config.assert_called_once_with(fake.EXTRA_SPEC)
|
||||
|
||||
@ddt.data(
|
||||
{'expected_server': fake.SHARE_SERVER_NO_DETAILS,
|
||||
'share_servers': [
|
||||
fake.SHARE_SERVER_NFS_TCP, fake.SHARE_SERVER_NO_DETAILS]},
|
||||
{'expected_server': fake.SHARE_SERVER_NO_NFS_NONE,
|
||||
'share_servers': [
|
||||
fake.SHARE_SERVER_NFS_UDP, fake.SHARE_SERVER_NO_NFS_NONE]},
|
||||
{'expected_server': fake.SHARE_SERVER_NFS_DEFAULT,
|
||||
'share_servers': [
|
||||
fake.SHARE_SERVER_NFS_UDP, fake.SHARE_SERVER_NFS_DEFAULT]},
|
||||
{'expected_server': None,
|
||||
'share_servers': [
|
||||
fake.SHARE_SERVER_NFS_TCP, fake.SHARE_SERVER_NFS_UDP]},
|
||||
{'expected_server': fake.SHARE_SERVER_NO_DETAILS,
|
||||
'share_servers': [fake.SHARE_SERVER_NO_DETAILS],
|
||||
'nfs_config_support': False}
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_choose_share_server_compatible_with_share_no_specification(
|
||||
self, expected_server, share_servers, nfs_config_support=True):
|
||||
self.library.is_nfs_config_supported = nfs_config_support
|
||||
mock_get_extra_spec = self.mock_object(
|
||||
share_types, "get_extra_specs_from_share",
|
||||
mock.Mock(return_value=fake.EMPTY_EXTRA_SPEC))
|
||||
mock_get_nfs_config = self.mock_object(
|
||||
self.library,
|
||||
"_get_nfs_config_provisioning_options",
|
||||
mock.Mock(return_value=fake.NFS_CONFIG_DEFAULT))
|
||||
|
||||
server = self.library.choose_share_server_compatible_with_share(
|
||||
None, share_servers, fake.SHARE)
|
||||
|
||||
self.assertEqual(expected_server, server)
|
||||
if nfs_config_support:
|
||||
mock_get_extra_spec.assert_called_once_with(fake.SHARE)
|
||||
mock_get_nfs_config.assert_called_once_with(fake.EMPTY_EXTRA_SPEC)
|
||||
|
||||
def test_manage_existing_error(self):
|
||||
fake_server = {'id': 'id'}
|
||||
fake_nfs_config = 'fake_nfs_config'
|
||||
self.library.is_nfs_config_supported = True
|
||||
|
||||
mock_get_extra_spec = self.mock_object(
|
||||
share_types, "get_extra_specs_from_share",
|
||||
mock.Mock(return_value=fake.EXTRA_SPEC))
|
||||
mock_get_nfs_config = self.mock_object(
|
||||
self.library,
|
||||
"_get_nfs_config_provisioning_options",
|
||||
mock.Mock(return_value=fake_nfs_config))
|
||||
mock_is_compatible = self.mock_object(
|
||||
self.library,
|
||||
"_is_share_server_compatible",
|
||||
mock.Mock(return_value=False))
|
||||
|
||||
self.assertRaises(exception.NetAppException,
|
||||
self.library.manage_existing,
|
||||
fake.SHARE, 'opts', fake_server)
|
||||
|
||||
mock_get_extra_spec.assert_called_once_with(fake.SHARE)
|
||||
mock_get_nfs_config.assert_called_once_with(fake.EXTRA_SPEC)
|
||||
mock_is_compatible.assert_called_once_with(fake_server,
|
||||
fake_nfs_config)
|
||||
|
||||
def test_choose_share_server_compatible_with_share_group_no_share_server(
|
||||
self):
|
||||
server = self.library.choose_share_server_compatible_with_share_group(
|
||||
None, [], fake.SHARE_GROUP_REF)
|
||||
|
||||
self.assertIsNone(server)
|
||||
|
||||
@ddt.data(
|
||||
[fake.NFS_CONFIG_DEFAULT, fake.NFS_CONFIG_TCP_MAX],
|
||||
[fake.NFS_CONFIG_TCP_MAX, fake.NFS_CONFIG_UDP_MAX],
|
||||
[fake.NFS_CONFIG_TCP_UDP_MAX, fake.NFS_CONFIG_TCP_MAX],
|
||||
[fake.NFS_CONFIG_DEFAULT, fake.NFS_CONFIG_TCP_UDP_MAX])
|
||||
def test_choose_share_server_compatible_with_share_group_nfs_conflict(
|
||||
self, nfs_config_list):
|
||||
self.library.is_nfs_config_supported = True
|
||||
self.mock_object(
|
||||
share_types, "get_share_type_extra_specs",
|
||||
mock.Mock(return_value=fake.EXTRA_SPEC))
|
||||
mock_get_nfs_config = self.mock_object(
|
||||
self.library,
|
||||
"_get_nfs_config_provisioning_options",
|
||||
mock.Mock(side_effect=nfs_config_list))
|
||||
mock_check_extra_spec = self.mock_object(
|
||||
self.library,
|
||||
'_check_nfs_config_extra_specs_validity',
|
||||
mock.Mock())
|
||||
|
||||
self.assertRaises(exception.InvalidInput,
|
||||
self.library.
|
||||
choose_share_server_compatible_with_share_group,
|
||||
None, fake.SHARE_SERVERS, fake.SHARE_GROUP_REF)
|
||||
|
||||
mock_get_nfs_config.assert_called_with(fake.EXTRA_SPEC)
|
||||
mock_check_extra_spec.assert_called_once_with(fake.EXTRA_SPEC)
|
||||
|
||||
@ddt.data(
|
||||
{'expected_server': fake.SHARE_SERVER_NO_DETAILS,
|
||||
'nfs_config': fake.NFS_CONFIG_DEFAULT,
|
||||
'share_servers': [
|
||||
fake.SHARE_SERVER_NFS_TCP, fake.SHARE_SERVER_NO_DETAILS]},
|
||||
{'expected_server': fake.SHARE_SERVER_NO_NFS_NONE,
|
||||
'nfs_config': fake.NFS_CONFIG_DEFAULT,
|
||||
'share_servers': [
|
||||
fake.SHARE_SERVER_NFS_UDP, fake.SHARE_SERVER_NO_NFS_NONE]},
|
||||
{'expected_server': fake.SHARE_SERVER_NFS_DEFAULT,
|
||||
'nfs_config': fake.NFS_CONFIG_DEFAULT,
|
||||
'share_servers': [
|
||||
fake.SHARE_SERVER_NFS_UDP, fake.SHARE_SERVER_NFS_DEFAULT]},
|
||||
{'expected_server': None,
|
||||
'nfs_config': fake.NFS_CONFIG_DEFAULT,
|
||||
'share_servers': [
|
||||
fake.SHARE_SERVER_NFS_TCP, fake.SHARE_SERVER_NFS_UDP,
|
||||
fake.SHARE_SERVER_NFS_TCP_UDP]},
|
||||
{'expected_server': fake.SHARE_SERVER_NFS_TCP_UDP,
|
||||
'nfs_config': fake.NFS_CONFIG_TCP_UDP_MAX,
|
||||
'share_servers': [
|
||||
fake.SHARE_SERVER_NFS_TCP, fake.SHARE_SERVER_NFS_UDP,
|
||||
fake.SHARE_SERVER_NFS_DEFAULT, fake.SHARE_SERVER_NFS_TCP_UDP]},
|
||||
{'expected_server': fake.NFS_CONFIG_DEFAULT,
|
||||
'nfs_config': None,
|
||||
'share_servers': [fake.NFS_CONFIG_DEFAULT],
|
||||
'nfs_config_supported': False}
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_choose_share_server_compatible_with_share_group(
|
||||
self, expected_server, nfs_config, share_servers,
|
||||
nfs_config_supported=True):
|
||||
self.library.is_nfs_config_supported = nfs_config_supported
|
||||
self.mock_object(
|
||||
share_types, "get_share_type_extra_specs",
|
||||
mock.Mock(return_value=fake.EXTRA_SPEC))
|
||||
mock_get_nfs_config = self.mock_object(
|
||||
self.library,
|
||||
"_get_nfs_config_provisioning_options",
|
||||
mock.Mock(return_value=nfs_config))
|
||||
mock_check_extra_spec = self.mock_object(
|
||||
self.library,
|
||||
'_check_nfs_config_extra_specs_validity',
|
||||
mock.Mock())
|
||||
|
||||
server = self.library.choose_share_server_compatible_with_share_group(
|
||||
None, share_servers, fake.SHARE_GROUP_REF)
|
||||
|
||||
if nfs_config_supported:
|
||||
mock_get_nfs_config.assert_called_with(fake.EXTRA_SPEC)
|
||||
mock_check_extra_spec.assert_called_once_with(fake.EXTRA_SPEC)
|
||||
else:
|
||||
mock_get_nfs_config.assert_not_called()
|
||||
mock_check_extra_spec.assert_not_called()
|
||||
self.assertEqual(expected_server, server)
|
||||
|
@ -14,6 +14,7 @@
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
from manila.common import constants
|
||||
import manila.tests.share.drivers.netapp.fakes as na_fakes
|
||||
@ -173,6 +174,64 @@ EXTRA_SPEC = {
|
||||
'netapp_disk_type': 'FCAL',
|
||||
'netapp_raid_type': 'raid4',
|
||||
'netapp_flexvol_encryption': 'true',
|
||||
'netapp:tcp_max_xfer_size': 100,
|
||||
'netapp:udp_max_xfer_size': 100,
|
||||
}
|
||||
|
||||
NFS_CONFIG_DEFAULT = {
|
||||
'tcp-max-xfer-size': 65536,
|
||||
'udp-max-xfer-size': 32768,
|
||||
}
|
||||
|
||||
NFS_CONFIG_TCP_MAX_DDT = {
|
||||
'extra_specs': {
|
||||
'netapp:tcp_max_xfer_size': 100,
|
||||
},
|
||||
'expected': {
|
||||
'tcp-max-xfer-size': 100,
|
||||
'udp-max-xfer-size': NFS_CONFIG_DEFAULT['udp-max-xfer-size'],
|
||||
}
|
||||
}
|
||||
|
||||
NFS_CONFIG_UDP_MAX_DDT = {
|
||||
'extra_specs': {
|
||||
'netapp:udp_max_xfer_size': 100,
|
||||
},
|
||||
'expected': {
|
||||
'tcp-max-xfer-size': NFS_CONFIG_DEFAULT['tcp-max-xfer-size'],
|
||||
'udp-max-xfer-size': 100,
|
||||
}
|
||||
}
|
||||
|
||||
NFS_CONFIG_TCP_UDP_MAX = {
|
||||
'tcp-max-xfer-size': 100,
|
||||
'udp-max-xfer-size': 100,
|
||||
}
|
||||
|
||||
NFS_CONFIG_TCP_MAX = {
|
||||
'tcp-max-xfer-size': 100,
|
||||
'udp-max-xfer-size': NFS_CONFIG_DEFAULT['udp-max-xfer-size'],
|
||||
}
|
||||
|
||||
NFS_CONFIG_UDP_MAX = {
|
||||
'tcp-max-xfer-size': NFS_CONFIG_DEFAULT['tcp-max-xfer-size'],
|
||||
'udp-max-xfer-size': 100,
|
||||
}
|
||||
|
||||
NFS_CONFIG_TCP_UDP_MAX_DDT = {
|
||||
'extra_specs': {
|
||||
'netapp:tcp_max_xfer_size': 100,
|
||||
'netapp:udp_max_xfer_size': 100,
|
||||
},
|
||||
'expected': NFS_CONFIG_TCP_UDP_MAX,
|
||||
}
|
||||
|
||||
SHARE_GROUP_REF = {
|
||||
'share_types': [
|
||||
{'share_type_id': 'id1'},
|
||||
{'share_type_id': 'id2'},
|
||||
{'share_type_id': 'id3'},
|
||||
],
|
||||
}
|
||||
|
||||
EXTRA_SPEC_WITH_QOS = copy.deepcopy(EXTRA_SPEC)
|
||||
@ -270,6 +329,14 @@ INVALID_MAX_FILE_EXTRA_SPEC = {
|
||||
'netapp:max_files': -1,
|
||||
}
|
||||
|
||||
INVALID_TCP_MAX_XFER_SIZE_EXTRA_SPEC = {
|
||||
'netapp:tcp_max_xfer_size': -1,
|
||||
}
|
||||
|
||||
INVALID_UDP_MAX_XFER_SIZE_EXTRA_SPEC = {
|
||||
'netapp:udp_max_xfer_size': -1,
|
||||
}
|
||||
|
||||
EMPTY_EXTRA_SPEC = {}
|
||||
|
||||
SHARE_TYPE = {
|
||||
@ -383,6 +450,58 @@ SHARE_SERVER_2 = {
|
||||
ADMIN_NETWORK_ALLOCATIONS),
|
||||
}
|
||||
|
||||
SHARE_SERVER_NFS_TCP = {
|
||||
'id': 'fake_nfs_id_tcp',
|
||||
'backend_details': {
|
||||
'vserver_name': VSERVER2,
|
||||
'nfs_config': jsonutils.dumps(NFS_CONFIG_TCP_MAX),
|
||||
},
|
||||
}
|
||||
|
||||
SHARE_SERVER_NFS_UDP = {
|
||||
'id': 'fake_nfs_id_udp',
|
||||
'backend_details': {
|
||||
'vserver_name': VSERVER2,
|
||||
'nfs_config': jsonutils.dumps(NFS_CONFIG_UDP_MAX),
|
||||
},
|
||||
}
|
||||
|
||||
SHARE_SERVER_NFS_TCP_UDP = {
|
||||
'id': 'fake_nfs_id_tcp_udp',
|
||||
'backend_details': {
|
||||
'vserver_name': VSERVER2,
|
||||
'nfs_config': jsonutils.dumps(NFS_CONFIG_TCP_UDP_MAX),
|
||||
},
|
||||
}
|
||||
|
||||
SHARE_SERVER_NO_NFS_NONE = {
|
||||
'id': 'fake_no_nfs_id_none',
|
||||
'backend_details': {
|
||||
'vserver_name': VSERVER2,
|
||||
},
|
||||
}
|
||||
|
||||
SHARE_SERVER_NO_DETAILS = {
|
||||
'id': 'id_no_datails',
|
||||
}
|
||||
|
||||
SHARE_SERVER_NFS_DEFAULT = {
|
||||
'id': 'fake_id_nfs_default',
|
||||
'backend_details': {
|
||||
'vserver_name': VSERVER2,
|
||||
'nfs_config': jsonutils.dumps(NFS_CONFIG_DEFAULT),
|
||||
},
|
||||
}
|
||||
|
||||
SHARE_SERVERS = [
|
||||
SHARE_SERVER_NFS_TCP,
|
||||
SHARE_SERVER_NFS_UDP,
|
||||
SHARE_SERVER_NFS_TCP_UDP,
|
||||
SHARE_SERVER_NFS_DEFAULT,
|
||||
SHARE_SERVER_NO_NFS_NONE,
|
||||
SHARE_SERVER_NO_DETAILS,
|
||||
]
|
||||
|
||||
VSERVER_PEER = [{
|
||||
'vserver': VSERVER1,
|
||||
'peer-vserver': VSERVER2,
|
||||
@ -1205,6 +1324,11 @@ PROCESSOR_INSTANCE_UUIDS = [
|
||||
]
|
||||
PROCESSOR_INSTANCE_NAMES = ['processor0', 'processor1']
|
||||
|
||||
SERVER_METADATA = {
|
||||
'share_type_id': 'fake_id',
|
||||
'host': 'fake_host',
|
||||
}
|
||||
|
||||
PROCESSOR_COUNTERS = [
|
||||
{
|
||||
'node-name': 'cluster1-01',
|
||||
|
@ -0,0 +1,12 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
For NetApp ONTAP driver, administrators are now able to set share servers
|
||||
max NFS transfer limits. These limits can be configured by setting the
|
||||
`netapp:tcp_max_xfer_size` and `netapp:udp_max_xfer_size` extra-specs.
|
||||
The driver will consider these limits while deciding to create or reuse
|
||||
share servers. While bringing a share under Manila management, the driver
|
||||
will check if the share type extra-specs values match the share server
|
||||
configured NFS limits. This change does not have effect in DHSS=False
|
||||
environments and relies on ONTAP features available only in versions equal
|
||||
to and greater than ``9.4``.
|
Loading…
x
Reference in New Issue
Block a user