cDOT driver should report all share export locations

Manila has the ability for shares to report multiple export locations.
This is an important capability for drivers that manage storage
backends that export shares on multiple network interfaces.  This
commit adds this capability to the cDOT driver.  This commit also
updates the cDOT driver to use backslashes in CIFS export paths.

Change-Id: I772caaad2871a072bb5bc4a505678d9fbf0c579c
Closes-Bug: #1429246
This commit is contained in:
Clinton Knight 2015-03-13 14:33:33 -04:00
parent 7b00db5f37
commit 725a9ced55
9 changed files with 79 additions and 30 deletions

View File

@ -488,9 +488,9 @@ class NetAppCmodeFileStorageLibrary(object):
msg_args = {'vserver': vserver, 'proto': share['share_proto']}
raise exception.NetAppException(msg % msg_args)
ip_address = interfaces[0]['address']
export_location = helper.create_share(share_name, ip_address)
return export_location
export_addresses = [interface['address'] for interface in interfaces]
export_locations = helper.create_share(share_name, export_addresses)
return export_locations
@na_utils.trace
def _remove_export(self, share, vserver_client):

View File

@ -29,7 +29,7 @@ class NetAppBaseHelper(object):
self._client = client
@abc.abstractmethod
def create_share(self, share, export_ip):
def create_share(self, share, export_addresses):
"""Creates NAS share."""
@abc.abstractmethod

View File

@ -15,6 +15,8 @@
NetApp CIFS protocol helper class.
"""
import re
from oslo_log import log
from manila import exception
@ -31,11 +33,12 @@ class NetAppCmodeCIFSHelper(base.NetAppBaseHelper):
"""Netapp specific cluster-mode CIFS sharing driver."""
@na_utils.trace
def create_share(self, share_name, export_ip):
def create_share(self, share_name, export_addresses):
"""Creates CIFS share on Data ONTAP Vserver."""
self._client.create_cifs_share(share_name)
self._client.remove_cifs_share_access(share_name, 'Everyone')
return "//%s/%s" % (export_ip, share_name)
return [r'\\%s\%s' % (export_address, share_name)
for export_address in export_addresses]
@na_utils.trace
def delete_share(self, share):
@ -84,6 +87,10 @@ class NetAppCmodeCIFSHelper(base.NetAppBaseHelper):
@staticmethod
def _get_export_location(share):
"""Returns host ip and share name for a given CIFS share."""
export_location = share['export_location'] or '///'
_x, _x, host_ip, share_name = export_location.split('/')
return host_ip, share_name
export_location = share['export_location'] or '\\\\\\'
regex = r'^(?:\\\\|//)(?P<host_ip>.*)(?:\\|/)(?P<share_name>.*)$'
match = re.match(regex, export_location)
if match:
return match.group('host_ip'), match.group('share_name')
else:
return '', ''

View File

@ -29,11 +29,11 @@ class NetAppCmodeNFSHelper(base.NetAppBaseHelper):
"""Netapp specific cluster-mode NFS sharing driver."""
@na_utils.trace
def create_share(self, share_name, export_ip):
def create_share(self, share_name, export_addresses):
"""Creates NFS share."""
export_path = self._client.get_volume_junction_path(share_name)
export_location = ':'.join([export_ip, export_path])
return export_location
return [':'.join([export_address, export_path])
for export_address in export_addresses]
@na_utils.trace
def delete_share(self, share):

View File

@ -790,7 +790,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
def test_create_export(self):
protocol_helper = mock.Mock()
protocol_helper.create_share.return_value = 'fake_export_location'
protocol_helper.create_share.return_value = fake.NFS_EXPORTS
self.mock_object(self.library,
'_get_helper',
mock.Mock(return_value=protocol_helper))
@ -802,10 +802,9 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
vserver_client)
share_name = self.library._get_valid_share_name(fake.SHARE['id'])
self.assertEqual('fake_export_location', result)
self.assertEqual(fake.NFS_EXPORTS, result)
protocol_helper.create_share.assert_called_once_with(
share_name,
fake.LIFS[0]['address'])
share_name, fake.LIF_ADDRESSES)
def test_create_export_lifs_not_found(self):

View File

@ -188,7 +188,7 @@ SNAPSHOT = {
}
LIF_NAMES = []
LIF_ADDRESSES = ('10.10.10.10', '10.10.10.20')
LIF_ADDRESSES = ['10.10.10.10', '10.10.10.20']
LIFS = (
{'address': LIF_ADDRESSES[0],
'home-node': CLUSTER_NODES[0],
@ -208,6 +208,9 @@ LIFS = (
},
)
NFS_EXPORTS = [':'.join([LIF_ADDRESSES[0], 'fake_export_path']),
':'.join([LIF_ADDRESSES[1], 'fake_export_path'])]
SHARE_ACCESS = {
'access_type': 'user',
'access_to': [LIF_ADDRESSES[0]]

View File

@ -15,18 +15,19 @@
SHARE_NAME = 'fake_share'
SHARE_ID = '9dba208c-9aa7-11e4-89d3-123b93f75cba'
SHARE_ADDRESS = '10.10.10.10'
SHARE_ADDRESS_1 = '10.10.10.10'
SHARE_ADDRESS_2 = '10.10.10.20'
CLIENT_ADDRESS_1 = '20.20.20.10'
CLIENT_ADDRESS_2 = '20.20.20.20'
CIFS_SHARE = {
'export_location': '//%s/%s' % (SHARE_ADDRESS, SHARE_NAME),
'export_location': r'\\%s\%s' % (SHARE_ADDRESS_1, SHARE_NAME),
'id': SHARE_ID
}
NFS_SHARE_PATH = '/%s' % SHARE_NAME
NFS_SHARE = {
'export_location': '%s:%s' % (SHARE_ADDRESS, NFS_SHARE_PATH),
'export_location': '%s:%s' % (SHARE_ADDRESS_1, NFS_SHARE_PATH),
'id': SHARE_ID
}

View File

@ -45,14 +45,29 @@ class NetAppClusteredCIFSHelperTestCase(test.TestCase):
def test_create_share(self):
result = self.helper.create_share(fake.SHARE_NAME, fake.SHARE_ADDRESS)
result = self.helper.create_share(fake.SHARE_NAME,
[fake.SHARE_ADDRESS_1])
expected = [r'\\%s\%s' % (fake.SHARE_ADDRESS_1, fake.SHARE_NAME)]
self.assertEqual(expected, result)
self.mock_client.create_cifs_share.assert_called_once_with(
fake.SHARE_NAME)
self.mock_client.remove_cifs_share_access.assert_called_once_with(
fake.SHARE_NAME, 'Everyone')
def test_create_share_multiple(self):
result = self.helper.create_share(fake.SHARE_NAME,
[fake.SHARE_ADDRESS_1,
fake.SHARE_ADDRESS_2])
expected = [r'\\%s\%s' % (fake.SHARE_ADDRESS_1, fake.SHARE_NAME),
r'\\%s\%s' % (fake.SHARE_ADDRESS_2, fake.SHARE_NAME)]
self.assertEqual(expected, result)
self.mock_client.create_cifs_share.assert_called_once_with(
fake.SHARE_NAME)
self.mock_client.remove_cifs_share_access.assert_called_once_with(
fake.SHARE_NAME, 'Everyone')
self.assertEqual('//%s/%s' % (fake.SHARE_ADDRESS, fake.SHARE_NAME),
result)
def test_delete_share(self):
@ -147,7 +162,7 @@ class NetAppClusteredCIFSHelperTestCase(test.TestCase):
def test_get_target(self):
target = self.helper.get_target(fake.CIFS_SHARE)
self.assertEqual(fake.SHARE_ADDRESS, target)
self.assertEqual(fake.SHARE_ADDRESS_1, target)
def test_get_target_missing_location(self):
@ -157,7 +172,17 @@ class NetAppClusteredCIFSHelperTestCase(test.TestCase):
def test_get_export_location(self):
host_ip, share_name = self.helper._get_export_location(fake.CIFS_SHARE)
self.assertEqual(fake.SHARE_ADDRESS, host_ip)
self.assertEqual(fake.SHARE_ADDRESS_1, host_ip)
self.assertEqual(fake.SHARE_NAME, share_name)
def test_get_export_location_legacy_forward_slashes(self):
fake_share = fake.CIFS_SHARE.copy()
fake_share['export_location'] = fake_share['export_location'].replace(
'\\', '/')
host_ip, share_name = self.helper._get_export_location(fake_share)
self.assertEqual(fake.SHARE_ADDRESS_1, host_ip)
self.assertEqual(fake.SHARE_NAME, share_name)
def test_get_export_location_missing_location(self):

View File

@ -41,10 +41,24 @@ class NetAppClusteredNFSHelperTestCase(test.TestCase):
self.mock_client.get_volume_junction_path.return_value = (
fake.NFS_SHARE_PATH)
result = self.helper.create_share(fake.SHARE_NAME, fake.SHARE_ADDRESS)
result = self.helper.create_share(fake.SHARE_NAME,
[fake.SHARE_ADDRESS_1])
self.assertEqual(':'.join([fake.SHARE_ADDRESS, fake.NFS_SHARE_PATH]),
result)
expected = [':'.join([fake.SHARE_ADDRESS_1, fake.NFS_SHARE_PATH])]
self.assertEqual(expected, result)
def test_create_share_multiple(self):
self.mock_client.get_volume_junction_path.return_value = (
fake.NFS_SHARE_PATH)
result = self.helper.create_share(fake.SHARE_NAME,
[fake.SHARE_ADDRESS_1,
fake.SHARE_ADDRESS_2])
expected = [':'.join([fake.SHARE_ADDRESS_1, fake.NFS_SHARE_PATH]),
':'.join([fake.SHARE_ADDRESS_2, fake.NFS_SHARE_PATH])]
self.assertEqual(expected, result)
def test_delete_share(self):
@ -123,7 +137,7 @@ class NetAppClusteredNFSHelperTestCase(test.TestCase):
def test_get_target(self):
target = self.helper.get_target(fake.NFS_SHARE)
self.assertEqual(fake.SHARE_ADDRESS, target)
self.assertEqual(fake.SHARE_ADDRESS_1, target)
def test_get_target_missing_location(self):
@ -154,7 +168,7 @@ class NetAppClusteredNFSHelperTestCase(test.TestCase):
host_ip, export_path = self.helper._get_export_location(
fake.NFS_SHARE)
self.assertEqual(fake.SHARE_ADDRESS, host_ip)
self.assertEqual(fake.SHARE_ADDRESS_1, host_ip)
self.assertEqual('/' + fake.SHARE_NAME, export_path)
def test_get_export_location_missing_location(self):