Advertise IPv6 support in the NetApp driver
Escape IPv6 exports correctly and setup the default export policy to allow both IPv4 and IPv6. Partially implements: bp netapp-ontap-ipv6-support Change-Id: I84437b140e2a9561cc4092683209800101f45815
This commit is contained in:
parent
5228e6ade7
commit
ebeca4c035
@ -126,4 +126,5 @@ class NetAppDriver(object):
|
||||
driver = importutils.import_object(driver_loc, *args, **kwargs)
|
||||
LOG.info('NetApp driver of family %(storage_family)s and mode '
|
||||
'%(driver_mode)s loaded.', fmt)
|
||||
driver.ipv6_implemented = True
|
||||
return driver
|
||||
|
@ -1269,7 +1269,7 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
||||
"""Enables NFS on Vserver."""
|
||||
self.send_request('nfs-enable')
|
||||
self._enable_nfs_protocols(versions)
|
||||
self._create_default_nfs_export_rule()
|
||||
self._create_default_nfs_export_rules()
|
||||
|
||||
@na_utils.trace
|
||||
def _enable_nfs_protocols(self, versions):
|
||||
@ -1286,7 +1286,7 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
||||
self.send_request('nfs-service-modify', nfs_service_modify_args)
|
||||
|
||||
@na_utils.trace
|
||||
def _create_default_nfs_export_rule(self):
|
||||
def _create_default_nfs_export_rules(self):
|
||||
"""Create the default export rule for the NFS service."""
|
||||
|
||||
export_rule_create_args = {
|
||||
@ -1300,6 +1300,8 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
||||
},
|
||||
}
|
||||
self.send_request('export-rule-create', export_rule_create_args)
|
||||
export_rule_create_args['client-match'] = '::/0'
|
||||
self.send_request('export-rule-create', export_rule_create_args)
|
||||
|
||||
@na_utils.trace
|
||||
def configure_ldap(self, security_service):
|
||||
@ -3652,3 +3654,15 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
||||
msg = 'Could not delete QoS policy groups. Details: %(ex)s'
|
||||
msg_args = {'ex': ex}
|
||||
LOG.debug(msg, msg_args)
|
||||
|
||||
@na_utils.trace
|
||||
def get_net_options(self):
|
||||
result = self.send_request('net-options-get', None, False)
|
||||
options = result.get_child_by_name('net-options')
|
||||
ipv6_enabled = False
|
||||
ipv6_info = options.get_child_by_name('ipv6-options-info')
|
||||
if ipv6_info:
|
||||
ipv6_enabled = ipv6_info.get_child_content('enabled') == 'true'
|
||||
return {
|
||||
'ipv6-enabled': ipv6_enabled,
|
||||
}
|
||||
|
@ -234,3 +234,6 @@ class NetAppCmodeMultiSvmShareDriver(driver.ShareDriver):
|
||||
snapshot_dict,
|
||||
fallback_create,
|
||||
share_server)
|
||||
|
||||
def get_configured_ip_version(self):
|
||||
return self.library.get_configured_ip_version()
|
||||
|
@ -250,3 +250,6 @@ class NetAppCmodeSingleSvmShareDriver(driver.ShareDriver):
|
||||
snapshot_dict,
|
||||
fallback_create,
|
||||
share_server)
|
||||
|
||||
def get_configured_ip_version(self):
|
||||
return self.library.get_configured_ip_version()
|
||||
|
@ -384,3 +384,10 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
|
||||
self._client.delete_vlan(node, port, vlan)
|
||||
except exception.NetAppException:
|
||||
LOG.exception("Deleting Vserver VLAN failed.")
|
||||
|
||||
def get_configured_ip_version(self):
|
||||
versions = [4]
|
||||
options = self._client.get_net_options()
|
||||
if options['ipv6-enabled']:
|
||||
versions.append(6)
|
||||
return versions
|
||||
|
@ -146,3 +146,22 @@ class NetAppCmodeSingleSVMFileStorageLibrary(
|
||||
def get_admin_network_allocations_number(self):
|
||||
"""Get number of network allocations for creating admin LIFs."""
|
||||
return 0
|
||||
|
||||
@na_utils.trace
|
||||
def get_configured_ip_version(self):
|
||||
ipv4 = False
|
||||
ipv6 = False
|
||||
vserver_client = self._get_api_client(vserver=self._vserver)
|
||||
interfaces = vserver_client.get_network_interfaces()
|
||||
for interface in interfaces:
|
||||
address = interface['address']
|
||||
if ':' in address:
|
||||
ipv6 = True
|
||||
else:
|
||||
ipv4 = True
|
||||
versions = []
|
||||
if ipv4:
|
||||
versions.append(4)
|
||||
if ipv6:
|
||||
versions.append(6)
|
||||
return versions
|
||||
|
@ -17,7 +17,6 @@ NetApp cDOT NFS protocol helper class.
|
||||
|
||||
import uuid
|
||||
|
||||
import netaddr
|
||||
from oslo_log import log
|
||||
import six
|
||||
|
||||
@ -33,6 +32,13 @@ LOG = log.getLogger(__name__)
|
||||
class NetAppCmodeNFSHelper(base.NetAppBaseHelper):
|
||||
"""NetApp cDOT NFS protocol helper class."""
|
||||
|
||||
@staticmethod
|
||||
def _escaped_address(address):
|
||||
if ':' in address:
|
||||
return '[%s]' % address
|
||||
else:
|
||||
return address
|
||||
|
||||
@na_utils.trace
|
||||
def create_share(self, share, share_name,
|
||||
clear_current_export_policy=True):
|
||||
@ -45,7 +51,8 @@ class NetAppCmodeNFSHelper(base.NetAppBaseHelper):
|
||||
# Return a callback that may be used for generating export paths
|
||||
# for this share.
|
||||
return (lambda export_address, export_path=export_path:
|
||||
':'.join([export_address, export_path]))
|
||||
':'.join([self._escaped_address(export_address),
|
||||
export_path]))
|
||||
|
||||
@na_utils.trace
|
||||
@base.access_rules_synchronized
|
||||
@ -67,7 +74,7 @@ class NetAppCmodeNFSHelper(base.NetAppBaseHelper):
|
||||
|
||||
# Sort rules by ascending network size
|
||||
new_rules = {rule['access_to']: rule['access_level'] for rule in rules}
|
||||
addresses = self._get_sorted_access_rule_addresses(new_rules)
|
||||
addresses = sorted(new_rules, reverse=True)
|
||||
|
||||
# Ensure current export policy has the name we expect
|
||||
self._ensure_export_policy(share, share_name)
|
||||
@ -123,22 +130,6 @@ class NetAppCmodeNFSHelper(base.NetAppBaseHelper):
|
||||
if rule['access_level'] not in constants.ACCESS_LEVELS:
|
||||
raise exception.InvalidShareAccessLevel(level=rule['access_level'])
|
||||
|
||||
@na_utils.trace
|
||||
def _get_sorted_access_rule_addresses(self, rules):
|
||||
"""Given a dict of access rules, sort by increasing network size."""
|
||||
|
||||
networks = sorted([self._get_network_object_from_rule(rule)
|
||||
for rule in rules], reverse=True)
|
||||
|
||||
return [six.text_type(network) for network in networks]
|
||||
|
||||
def _get_network_object_from_rule(self, rule):
|
||||
"""Get most appropriate netaddr object for address or network rule."""
|
||||
try:
|
||||
return netaddr.IPAddress(rule)
|
||||
except ValueError:
|
||||
return netaddr.IPNetwork(rule)
|
||||
|
||||
@na_utils.trace
|
||||
def get_target(self, share):
|
||||
"""Returns ID of target OnTap device based on export location."""
|
||||
|
@ -2176,14 +2176,14 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
||||
|
||||
self.mock_object(self.client, 'send_request')
|
||||
self.mock_object(self.client, '_enable_nfs_protocols')
|
||||
self.mock_object(self.client, '_create_default_nfs_export_rule')
|
||||
self.mock_object(self.client, '_create_default_nfs_export_rules')
|
||||
|
||||
self.client.enable_nfs(fake.NFS_VERSIONS)
|
||||
|
||||
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_rule.assert_called_once_with()
|
||||
self.client._create_default_nfs_export_rules.assert_called_once_with()
|
||||
|
||||
@ddt.data((True, True, True), (True, False, False), (False, True, True))
|
||||
@ddt.unpack
|
||||
@ -2209,11 +2209,17 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
||||
self.client.send_request.assert_called_once_with(
|
||||
'nfs-service-modify', nfs_service_modify_args)
|
||||
|
||||
def test_create_default_nfs_export_rule(self):
|
||||
def test_create_default_nfs_export_rules(self):
|
||||
|
||||
self.mock_object(self.client, 'send_request')
|
||||
class CopyingMock(mock.Mock):
|
||||
def __call__(self, *args, **kwargs):
|
||||
args = copy.deepcopy(args)
|
||||
kwargs = copy.deepcopy(kwargs)
|
||||
return super(CopyingMock, self).__call__(*args, **kwargs)
|
||||
|
||||
self.client._create_default_nfs_export_rule()
|
||||
self.mock_object(self.client, 'send_request', CopyingMock())
|
||||
|
||||
self.client._create_default_nfs_export_rules()
|
||||
|
||||
export_rule_create_args = {
|
||||
'client-match': '0.0.0.0/0',
|
||||
@ -2225,8 +2231,11 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
||||
'security-flavor': 'never'
|
||||
}
|
||||
}
|
||||
self.client.send_request.assert_called_once_with(
|
||||
'export-rule-create', export_rule_create_args)
|
||||
export_rule_create_args2 = export_rule_create_args.copy()
|
||||
export_rule_create_args2['client-match'] = '::/0'
|
||||
self.client.send_request.assert_has_calls([
|
||||
mock.call('export-rule-create', export_rule_create_args),
|
||||
mock.call('export-rule-create', export_rule_create_args2)])
|
||||
|
||||
def test_configure_ldap(self):
|
||||
|
||||
|
@ -20,7 +20,6 @@ import uuid
|
||||
|
||||
import ddt
|
||||
import mock
|
||||
import netaddr
|
||||
|
||||
from manila import exception
|
||||
from manila.share.drivers.netapp.dataontap.protocols import nfs_cmode
|
||||
@ -40,6 +39,11 @@ class NetAppClusteredNFSHelperTestCase(test.TestCase):
|
||||
self.helper = nfs_cmode.NetAppCmodeNFSHelper()
|
||||
self.helper.set_client(self.mock_client)
|
||||
|
||||
@ddt.data(('1.2.3.4', '1.2.3.4'), ('fc00::1', '[fc00::1]'))
|
||||
@ddt.unpack
|
||||
def test__escaped_address(self, raw, escaped):
|
||||
self.assertEqual(escaped, self.helper._escaped_address(raw))
|
||||
|
||||
def test_create_share(self):
|
||||
|
||||
mock_ensure_export_policy = self.mock_object(self.helper,
|
||||
@ -121,35 +125,6 @@ class NetAppClusteredNFSHelperTestCase(test.TestCase):
|
||||
self.helper._validate_access_rule,
|
||||
rule)
|
||||
|
||||
def test_get_sorted_access_rule_addresses(self):
|
||||
|
||||
result = self.helper._get_sorted_access_rule_addresses(
|
||||
fake.NEW_NFS_RULES)
|
||||
|
||||
expected = [
|
||||
'10.10.20.10',
|
||||
'10.10.20.0/24',
|
||||
'10.10.10.10',
|
||||
'10.10.10.0/30',
|
||||
'10.10.10.0/24',
|
||||
]
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
@ddt.data({'rule': '1.2.3.4', 'out': netaddr.IPAddress('1.2.3.4')},
|
||||
{'rule': '1.2.3.4/32', 'out': netaddr.IPNetwork('1.2.3.4/32')})
|
||||
@ddt.unpack
|
||||
def test_get_network_object_from_rule(self, rule, out):
|
||||
|
||||
result = self.helper._get_network_object_from_rule(rule)
|
||||
|
||||
self.assertEqual(out, result)
|
||||
|
||||
def test_get_network_object_from_rule_invalid(self):
|
||||
|
||||
self.assertRaises(netaddr.AddrFormatError,
|
||||
self.helper._get_network_object_from_rule,
|
||||
'invalid')
|
||||
|
||||
def test_get_target(self):
|
||||
|
||||
target = self.helper.get_target(fake.NFS_SHARE)
|
||||
|
@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
Added support for IPv6 export location and access rules to
|
||||
the NetApp driver.
|
Loading…
x
Reference in New Issue
Block a user