glusterfs*: amend export location

The basic problem is that determining the
export location of a share should happen in
driver scope (as it depends on available
export mechanims, which are implemented by
the driver) while the code did it in layout
scope in ad-hoc ways. Also in native driver
the export location was abused to store the
address of the backing GlusterFS resource.

Fix these by

-  layout:
   - GlusterfsShareDriverBase._setup_via_manager
     (the layer -> driver reverse callback) will
     provide the export location as return value
   - the share object is also passed to
     GlusterfsShareDriverBase._setup_via_manager
     (besides the gluster manager), because some
     driver configs will need it to specify the
     export location
-  glusterfs-native:
   - free the code from using export location
     (apart from composing it in _setup_via_manager);
     store the address of backing resource in
     private storage instead of the export location
     field
-  glusterfs:
   - define the `get_export` method for the export
     helpers that provide the export location
   - _setup_via_manager determines export location
     by calling the helper's get_export

Change-Id: Id02e4908a3e8e435c4c51ecacb6576785ac8afb6
Closes-Bug: #1476774
Closes-Bug: #1493080
This commit is contained in:
Csaba Henk 2015-09-17 22:00:07 +02:00
parent 24125c9884
commit bd146a841d
9 changed files with 162 additions and 73 deletions

View File

@ -25,6 +25,7 @@ TODO(rraja): support SMB protocol.
"""
import re
import socket
import sys
from oslo_config import cfg
@ -91,7 +92,8 @@ class GlusterfsShareDriver(driver.ExecuteMixin, driver.GaneshaMixin,
self._get_helper()
super(GlusterfsShareDriver, self).do_setup(context)
def _setup_via_manager(self, gluster_manager, gluster_manager_parent=None):
def _setup_via_manager(self, share_manager, share_manager_parent=None):
gluster_manager = share_manager['manager']
# exporting the whole volume must be prohibited
# to not to defeat access control
args = ('volume', 'set', gluster_manager.volume, NFS_EXPORT_VOL,
@ -103,6 +105,9 @@ class GlusterfsShareDriver(driver.ExecuteMixin, driver.GaneshaMixin,
"exporting the entire volume: %s"), exc.stderr)
raise exception.GlusterfsException("gluster %s failed" %
' '.join(args))
return self.nfs_helper(self._execute, self.configuration,
gluster_manager=gluster_manager).get_export(
share_manager['share'])
def check_for_setup_error(self):
pass
@ -146,6 +151,9 @@ class GlusterNFSHelper(ganesha.NASHelperBase):
super(GlusterNFSHelper, self).__init__(execute, config_object,
**kwargs)
def get_export(self, share):
return self.gluster_manager.export
def _get_export_dir_dict(self):
"""Get the export entries of shares in the GlusterFS volume."""
export_dir = self.gluster_manager.get_gluster_vol_option(
@ -252,13 +260,16 @@ class GaneshaNFSHelper(ganesha.GaneshaNASHelper):
privatekey=config_object.glusterfs_path_to_private_key)
else:
execute = ganesha_utils.RootExecutor(execute)
ganesha_host = config_object.glusterfs_ganesha_server_ip
if not ganesha_host:
ganesha_host = 'localhost'
kwargs['tag'] = '-'.join(('GLUSTER', 'Ganesha', ganesha_host))
self.ganesha_host = config_object.glusterfs_ganesha_server_ip
if not self.ganesha_host:
self.ganesha_host = socket.gethostname()
kwargs['tag'] = '-'.join(('GLUSTER', 'Ganesha', self.ganesha_host))
super(GaneshaNFSHelper, self).__init__(execute, config_object,
**kwargs)
def get_export(self, share):
return ':/'.join((self.ganesha_host, share['name']))
def init_helper(self):
@utils.synchronized(self.tag)
def _init_helper():

View File

@ -65,7 +65,7 @@ class GlusterfsShareDriverBase(driver.ShareDriver):
self.layout = importutils.import_object(
'.'.join((self.LAYOUT_PREFIX, layout_name)),
self, configuration=self.configuration)
self, **kwargs)
# we determine snapshot support in our own scope, as
# 1) the calculation based on parent method
# redefinition does not work for us, as actual
@ -78,17 +78,21 @@ class GlusterfsShareDriverBase(driver.ShareDriver):
'_snapshots_are_supported',
False)
def _setup_via_manager(self, gluster_mgr, gluster_mgr_parent=None):
def _setup_via_manager(self, share_mgr, share_mgr_parent=None):
"""Callback for layout's `create_share` and `create_share_from_snapshot`
:param gluster_mgr: GlusterManager instance
representing the GlusterFS resource that backs
the share created in `create_share` or
`create_share_from_snapshot`.
:param gluster_mgr_parent: GlusterManager instance
:param share_mgr: a {'share': <share>, 'manager': <gmgr>}
dict where <share> is the share created
in `create_share` or `create_share_from_snapshot`
and <gmgr> is a GlusterManager instance
representing the GlusterFS resource
that backs the share the snapshot of which
was used in `create_share_from_snapshot`.
allocated for it.
:param gluster_mgr_parent: a {'share': <share>, 'manager': <gmgr>}
dict where <share> is the original share of the snapshot
used in `create_share_from_snapshot` and <gmgr> is a
GlusterManager instance representing the GlusterFS
resource allocated for it.
:returns: export location for share_mgr['share'].
"""
def allow_access(self, context, share, access, share_server=None):

View File

@ -161,8 +161,12 @@ class GlusterfsDirectoryMappedLayout(layout.GlusterfsShareLayoutBase):
LOG.error(_LE('Unable to create share %s'), share['name'])
raise exception.GlusterfsException(exc)
export_location = os.path.join(self.gluster_manager.qualified,
share['name'])
comp_share = self.gluster_manager.components.copy()
comp_share['path'] = '/' + share['name']
export_location = self.driver._setup_via_manager(
{'share': share,
'manager': self._glustermanager(comp_share)})
return export_location
def _cleanup_create_share(self, share_path, share_name):

View File

@ -106,6 +106,7 @@ class GlusterfsVolumeMappedLayout(layout.GlusterfsShareLayoutBase):
# format check for srvaddr
self._glustermanager(srvaddr, False)
self.glusterfs_versions = {}
self.private_storage = kwargs.get('private_storage')
def _compile_volume_pattern(self):
"""Compile a RegexObject from the config specified regex template.
@ -191,7 +192,8 @@ class GlusterfsVolumeMappedLayout(layout.GlusterfsShareLayoutBase):
def _share_manager(self, share):
"""Return GlusterManager object representing share's backend."""
return self._glustermanager(share['export_location'])
return self._glustermanager(self.private_storage.get(
share['id'], 'volume'))
def _fetch_gluster_volumes(self):
"""Do a 'gluster volume list | grep <volume pattern>'.
@ -325,7 +327,6 @@ class GlusterfsVolumeMappedLayout(layout.GlusterfsShareLayoutBase):
# Within a host's volumes, choose alphabetically first,
# to make it predictable.
vol = sorted(chosen_hostmap[chosen_host])[0]
self.driver._setup_via_manager(self._glustermanager(vol))
self.gluster_used_vols.add(vol)
return vol
@ -389,20 +390,24 @@ class GlusterfsVolumeMappedLayout(layout.GlusterfsShareLayoutBase):
GlusterFS volume for use as a share.
"""
try:
export_location = self._pop_gluster_vol(share['size'])
vol = self._pop_gluster_vol(share['size'])
except exception.GlusterfsException:
msg = (_LE("Error creating share %(share_id)s"),
{'share_id': share['id']})
LOG.error(msg)
raise
export = self.driver._setup_via_manager(
{'share': share, 'manager': self._glustermanager(vol)})
self.private_storage.update(share['id'], {'volume': vol})
# TODO(deepakcs): Enable quota and set it to the share size.
# For native protocol, the export_location should be of the form:
# server:/volname
LOG.info(_LI("export_location sent back from create_share: %s"),
(export_location,))
return export_location
export)
return export
def delete_share(self, context, share, share_server=None):
"""Delete a share on the GlusterFS volume.
@ -420,6 +425,7 @@ class GlusterfsVolumeMappedLayout(layout.GlusterfsShareLayoutBase):
LOG.error(msg)
raise
self.private_storage.delete(share['id'])
# TODO(deepakcs): Disable quota.
@staticmethod
@ -484,9 +490,12 @@ class GlusterfsVolumeMappedLayout(layout.GlusterfsShareLayoutBase):
comp_vol = old_gmgr.components.copy()
comp_vol.update({'volume': volume})
gmgr = self._glustermanager(comp_vol)
self.driver._setup_via_manager(gmgr, old_gmgr)
export = self.driver._setup_via_manager(
{'share': share, 'manager': gmgr},
{'share': snapshot['share_instance'], 'manager': old_gmgr})
self.gluster_used_vols.add(gmgr.qualified)
return gmgr.qualified
self.private_storage.update(share['id'], {'volume': gmgr.qualified})
return export
def create_snapshot(self, context, snapshot, share_server=None):
"""Creates a snapshot."""

View File

@ -72,9 +72,12 @@ class GlusterfsNativeShareDriver(driver.ExecuteMixin,
self.backend_name = self.configuration.safe_get(
'share_backend_name') or 'GlusterFS-Native'
def _setup_via_manager(self, gluster_mgr, gluster_mgr_parent=None):
def _setup_via_manager(self, share_mgr, share_mgr_parent=None):
# Enable gluster volumes for SSL access only.
gluster_mgr = share_mgr['manager']
gluster_mgr_parent = (share_mgr_parent or {}).get('manager', None)
ssl_allow_opt = (gluster_mgr_parent if gluster_mgr_parent else
gluster_mgr).get_gluster_vol_option(
AUTH_SSL_ALLOW)
@ -136,6 +139,8 @@ class GlusterfsNativeShareDriver(driver.ExecuteMixin,
LOG.error(msg)
raise exception.GlusterfsException(msg)
return gluster_mgr.export
@utils.synchronized("glusterfs_native_access", external=False)
def _allow_access_via_manager(self, gluster_mgr, context, share, access,
share_server=None):

View File

@ -232,20 +232,32 @@ class GlusterfsDirectoryMappedLayoutTestCase(test.TestCase):
self.assertRaises(exception.GlusterfsException,
self._layout._update_share_stats)
def test_create_share(self):
@ddt.data((), (None,))
def test_create_share(self, extra_args):
exec_cmd1 = 'mkdir %s' % fake_local_share_path
expected_exec = [exec_cmd1, ]
expected_ret = 'testuser@127.0.0.1:/testvol/fakename'
self.mock_object(
self._layout, '_get_local_share_path',
mock.Mock(return_value=fake_local_share_path))
gmgr = mock.Mock()
self.mock_object(
self._layout, '_glustermanager', mock.Mock(return_value=gmgr))
self.mock_object(
self._layout.driver, '_setup_via_manager',
mock.Mock(return_value=expected_ret))
ret = self._layout.create_share(self._context, self.share)
ret = self._layout.create_share(self._context, self.share, *extra_args)
self._layout._get_local_share_path.called_once_with(self.share)
self._layout.gluster_manager.gluster_call.assert_called_once_with(
'volume', 'quota', 'testvol', 'limit-usage', '/fakename', '1GB')
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
self._layout._glustermanager.assert_called_once_with(
{'user': 'testuser', 'host': '127.0.0.1',
'volume': 'testvol', 'path': '/fakename'})
self._layout.driver._setup_via_manager.assert_called_once_with(
{'share': self.share, 'manager': gmgr})
self.assertEqual(expected_ret, ret)
def test_create_share_unable_to_create_share(self):
@ -271,21 +283,6 @@ class GlusterfsDirectoryMappedLayoutTestCase(test.TestCase):
layout_directory.LOG.error.assert_called_once_with(
mock.ANY, mock.ANY)
def test_create_share_can_be_called_with_extra_arg_share_server(self):
self._layout._get_local_share_path = mock.Mock()
with mock.patch.object(os.path, 'join', return_value=None):
share_server = None
ret = self._layout.create_share(self._context, self.share,
share_server)
self.assertIsNone(ret)
self._layout._get_local_share_path.called_once_with(self.share)
self._layout._get_local_share_path.assert_called_once_with(
self.share)
os.path.join.assert_called_once_with(
self._layout.gluster_manager.qualified, self.share['name'])
def test_cleanup_create_share_local_share_path_exists(self):
expected_exec = ['rm -rf %s' % fake_local_share_path]
self.mock_object(os.path, 'exists', mock.Mock(return_value=True))

View File

@ -114,11 +114,14 @@ class GlusterfsVolumeMappedLayoutTestCase(test.TestCase):
mock.Mock(return_value='/tmp/tmpKGHKJ'))
self.mock_object(common.GlusterManager, 'make_gluster_call')
self.fake_private_storage = mock.Mock()
with mock.patch.object(layout_volume.GlusterfsVolumeMappedLayout,
'_glustermanager',
side_effect=[self.gmgr1, self.gmgr2]):
self._layout = layout_volume.GlusterfsVolumeMappedLayout(
self.fake_driver, configuration=self.fake_conf)
self.fake_driver, configuration=self.fake_conf,
private_storage=self.fake_private_storage)
self._layout.glusterfs_versions = {self.glusterfs_server1: ('3', '6'),
self.glusterfs_server2: ('3', '7')}
self.addCleanup(fake_utils.fake_execute_set_repliers, [])
@ -275,12 +278,15 @@ class GlusterfsVolumeMappedLayoutTestCase(test.TestCase):
def test_share_manager(self):
self.mock_object(self._layout, '_glustermanager',
mock.Mock(return_value=self.gmgr1))
self.mock_object(self._layout.private_storage,
'get', mock.Mock(return_value='host1:/gv1'))
ret = self._layout._share_manager(self.share1)
self._layout.private_storage.get.assert_called_once_with(
self.share1['id'], 'volume')
self._layout._glustermanager.assert_called_once_with('host1:/gv1')
self.assertEqual(self.gmgr1, ret)
self._layout._glustermanager.assert_called_once_with(
self.share1['export_location'])
def test_ensure_share(self):
share = self.share1
@ -329,11 +335,7 @@ class GlusterfsVolumeMappedLayoutTestCase(test.TestCase):
self.assertEqual(expected, result)
self.assertIn(result, used_vols)
self._layout._fetch_gluster_volumes.assert_called_once_with()
self.assertEqual(
[mock.call(result), mock.call(result)],
self._layout._glustermanager.call_args_list
)
self.fake_driver._setup_via_manager.assert_called_once_with(gmgr1)
self._layout._glustermanager.assert_called_once_with(result)
@ddt.data({"voldict": {"share2G": {"size": 2}},
"used_vols": set(), "size": 3},
@ -471,12 +473,20 @@ class GlusterfsVolumeMappedLayoutTestCase(test.TestCase):
def test_create_share(self):
self._layout._pop_gluster_vol = mock.Mock(
return_value=self.glusterfs_target1)
self.mock_object(self._layout, '_glustermanager',
mock.Mock(return_value=self.gmgr1))
self.mock_object(self.fake_driver, '_setup_via_manager',
mock.Mock(return_value='host1:/gv1'))
share = new_share()
exp_locn = self._layout.create_share(self._context, share)
self.assertEqual(exp_locn, self.glusterfs_target1)
self._layout._pop_gluster_vol.assert_called_once_with(share['size'])
self.fake_driver._setup_via_manager.assert_called_once_with(
{'manager': self.gmgr1, 'share': share})
self._layout.private_storage.update.assert_called_once_with(
share['id'], {'volume': self.glusterfs_target1})
self.assertEqual('host1:/gv1', exp_locn)
def test_create_share_error(self):
self._layout._pop_gluster_vol = mock.Mock(
@ -503,6 +513,8 @@ class GlusterfsVolumeMappedLayoutTestCase(test.TestCase):
self._layout._wipe_gluster_vol.assert_called_once_with(gmgr1)
self._layout._push_gluster_vol.assert_called_once_with(
self.glusterfs_target1)
self._layout.private_storage.delete.assert_called_once_with(
self.share1['id'])
def test_delete_share_error(self):
self._layout._wipe_gluster_vol = mock.Mock()
@ -612,10 +624,14 @@ class GlusterfsVolumeMappedLayoutTestCase(test.TestCase):
@ddt.unpack
def test_create_snapshot_no_snap_cached(self, vers_minor, exctype):
self._layout.gluster_nosnap_vols_dict = {
self.share1['export_location']: 'fake error'}
self.glusterfs_target1: 'fake error'}
self._layout.glusterfs_versions = {
self.glusterfs_server1: ('3', vers_minor)}
self._layout.gluster_used_vols = set([self.glusterfs_target1])
gmgr = common.GlusterManager
gmgr1 = gmgr(self.glusterfs_target1, self._execute, None, None)
self.mock_object(self._layout, '_share_manager',
mock.Mock(return_value=gmgr1))
snapshot = {
'id': 'fake_snap_id',
@ -690,10 +706,10 @@ class GlusterfsVolumeMappedLayoutTestCase(test.TestCase):
'share_instance': new_share(export_location=glusterfs_target)
}
volume = ''.join(['manila-', share['id']])
new_export_location = ':/'.join([glusterfs_server, volume])
new_vol_addr = ':/'.join([glusterfs_server, volume])
gmgr = common.GlusterManager
old_gmgr = gmgr(glusterfs_target, self._execute, None, None)
new_gmgr = gmgr(new_export_location, self._execute, None, None)
new_gmgr = gmgr(new_vol_addr, self._execute, None, None)
self._layout.gluster_used_vols = set([glusterfs_target])
self._layout.glusterfs_versions = {glusterfs_server: ('3', '7')}
self.mock_object(old_gmgr, 'gluster_call',
@ -710,6 +726,8 @@ class GlusterfsVolumeMappedLayoutTestCase(test.TestCase):
mock.Mock(return_value=old_gmgr))
self.mock_object(self._layout, '_glustermanager',
mock.Mock(return_value=new_gmgr))
self.mock_object(self.fake_driver, '_setup_via_manager',
mock.Mock(return_value='host1:/gv1'))
ret = self._layout.create_share_from_snapshot(
self._context, share, snapshot, None)
@ -723,23 +741,26 @@ class GlusterfsVolumeMappedLayoutTestCase(test.TestCase):
self._layout._share_manager.assert_called_once_with(
snapshot['share_instance'])
self._layout._glustermanager.assert_called_once_with(
gmgr.parse(new_export_location))
gmgr.parse(new_vol_addr))
self._layout.driver._setup_via_manager.assert_called_once_with(
new_gmgr, old_gmgr)
{'manager': new_gmgr, 'share': share},
{'manager': old_gmgr, 'share': snapshot['share_instance']})
self._layout.private_storage.update.assert_called_once_with(
share['id'], {'volume': new_vol_addr})
self.assertIn(
new_export_location,
new_vol_addr,
self._layout.gluster_used_vols)
self.assertEqual(new_export_location, ret)
self.assertEqual('host1:/gv1', ret)
def test_create_share_from_snapshot_error_old_gmr_gluster_calls(self):
glusterfs_target = 'root@host1:/gv1'
glusterfs_server = 'root@host1'
share = new_share()
volume = ''.join(['manila-', share['id']])
new_export_location = ':/'.join([glusterfs_server, volume])
new_vol_addr = ':/'.join([glusterfs_server, volume])
gmgr = common.GlusterManager
old_gmgr = gmgr(glusterfs_target, self._execute, None, None)
new_gmgr = gmgr(new_export_location, self._execute, None, None)
new_gmgr = gmgr(new_vol_addr, self._execute, None, None)
self._layout.gluster_used_vols_dict = {glusterfs_target: old_gmgr}
self._layout.glusterfs_versions = {glusterfs_server: ('3', '7')}
self.mock_object(
@ -776,7 +797,7 @@ class GlusterfsVolumeMappedLayoutTestCase(test.TestCase):
snapshot['share_instance'])
self.assertFalse(new_gmgr.get_gluster_vol_option.called)
self.assertFalse(new_gmgr.gluster_call.called)
self.assertNotIn(new_export_location,
self.assertNotIn(new_vol_addr,
self._layout.glusterfs_versions.keys())
def test_create_share_from_snapshot_error_unsupported_gluster_version(
@ -785,10 +806,10 @@ class GlusterfsVolumeMappedLayoutTestCase(test.TestCase):
glusterfs_server = 'root@host1'
share = new_share()
volume = ''.join(['manila-', share['id']])
new_export_location = ':/'.join([glusterfs_server, volume])
new_vol_addr = ':/'.join([glusterfs_server, volume])
gmgr = common.GlusterManager
old_gmgr = gmgr(glusterfs_target, self._execute, None, None)
new_gmgr = gmgr(new_export_location, self._execute, None, None)
new_gmgr = gmgr(new_vol_addr, self._execute, None, None)
self._layout.gluster_used_vols_dict = {glusterfs_target: old_gmgr}
self._layout.glusterfs_versions = {glusterfs_server: ('3', '6')}
self.mock_object(
@ -824,7 +845,7 @@ class GlusterfsVolumeMappedLayoutTestCase(test.TestCase):
self.assertFalse(self._layout._glustermanager.called)
self.assertFalse(new_gmgr.get_gluster_vol_option.called)
self.assertFalse(new_gmgr.gluster_call.called)
self.assertNotIn(new_export_location,
self.assertNotIn(new_vol_addr,
self._layout.glusterfs_versions.keys())
def test_delete_snapshot(self):

View File

@ -14,6 +14,7 @@
# under the License.
import copy
import socket
import ddt
import mock
@ -85,13 +86,21 @@ class GlusterfsShareDriverTestCase(test.TestCase):
def test_setup_via_manager(self, has_parent):
gmgr = mock.Mock()
gmgr.gluster_call = mock.Mock()
gmgr_parent = mock.Mock() if has_parent else None
share_mgr_parent = mock.Mock() if has_parent else None
nfs_helper = mock.Mock()
nfs_helper.get_export = mock.Mock(return_value='host:/vol')
self._driver.nfs_helper = mock.Mock(return_value=nfs_helper)
self._driver._setup_via_manager(
gmgr, gluster_manager_parent=gmgr_parent)
ret = self._driver._setup_via_manager(
{'manager': gmgr, 'share': self.share},
share_manager_parent=share_mgr_parent)
gmgr.gluster_call.assert_called_once_with(
'volume', 'set', gmgr.volume, 'nfs.export-volumes', 'off')
self._driver.nfs_helper.assert_called_once_with(
self._execute, self.fake_conf, gluster_manager=gmgr)
nfs_helper.get_export.assert_called_once_with(self.share)
self.assertEqual('host:/vol', ret)
@ddt.data(exception.ProcessExecutionError, RuntimeError)
def test_setup_via_manager_exception(self, _exception):
@ -102,7 +111,8 @@ class GlusterfsShareDriverTestCase(test.TestCase):
self.assertRaises(
{exception.ProcessExecutionError:
exception.GlusterfsException}.get(
_exception, _exception), self._driver._setup_via_manager, gmgr)
_exception, _exception), self._driver._setup_via_manager,
{'manager': gmgr, 'share': self.share})
def test_check_for_setup_error(self):
self._driver.check_for_setup_error()
@ -160,6 +170,11 @@ class GlusterNFSHelperTestCase(test.TestCase):
self._helper = glusterfs.GlusterNFSHelper(
self._execute, self.fake_conf, gluster_manager=gluster_manager)
def test_get_export(self):
ret = self._helper.get_export(mock.Mock())
self.assertEqual(fake_gluster_manager_attrs['export'], ret)
def test_get_export_dir_dict(self):
output_str = '/foo(10.0.0.1|10.0.0.2),/bar(10.0.0.1)'
self.mock_object(self._helper.gluster_manager,
@ -359,6 +374,7 @@ class GaneshaNFSHelperTestCase(test.TestCase):
mock.Mock(return_value=self._root_execute))
self.mock_object(glusterfs.ganesha.GaneshaNASHelper, '__init__',
mock.Mock())
socket.gethostname = mock.Mock(return_value='example.com')
self._helper = glusterfs.GaneshaNFSHelper(
self._execute, self.fake_conf,
gluster_manager=self.gluster_manager)
@ -367,9 +383,15 @@ class GaneshaNFSHelperTestCase(test.TestCase):
def test_init_local_ganesha_server(self):
glusterfs.ganesha_utils.RootExecutor.assert_called_once_with(
self._execute)
socket.gethostname.assert_has_calls([mock.call()])
glusterfs.ganesha.GaneshaNASHelper.__init__.assert_has_calls(
[mock.call(self._root_execute, self.fake_conf,
tag='GLUSTER-Ganesha-localhost')])
tag='GLUSTER-Ganesha-example.com')])
def test_get_export(self):
ret = self._helper.get_export(self.share)
self.assertEqual('example.com:/fakename', ret)
def test_init_remote_ganesha_server(self):
ssh_execute = mock.Mock(return_value=('', ''))

View File

@ -102,10 +102,13 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
gmgr = mock.Mock()
gmgr.gluster_call = mock.Mock()
gmgr.volume = 'fakevol'
gmgr.export = 'fakehost:/fakevol'
gmgr.get_gluster_vol_option = mock.Mock(
return_value='glusterfs-server-name,some-other-name')
share = mock.Mock()
self._driver._setup_via_manager(gmgr)
ret = self._driver._setup_via_manager({'manager': gmgr,
'share': share})
gmgr.get_gluster_vol_option.assert_called_once_with('auth.ssl-allow')
args = (
@ -115,16 +118,22 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
('volume', 'stop', 'fakevol', '--mode=script'),
('volume', 'start', 'fakevol'))
gmgr.gluster_call.assert_has_calls([mock.call(*a) for a in args])
self.assertEqual(ret, gmgr.export)
def test_setup_via_manager_with_parent(self):
gmgr = mock.Mock()
gmgr.gluster_call = mock.Mock()
gmgr.volume = 'fakevol'
gmgr.export = 'fakehost:/fakevol'
gmgr_parent = mock.Mock()
gmgr_parent.get_gluster_vol_option = mock.Mock(
return_value='glusterfs-server-name,some-other-name')
share = mock.Mock()
share_parent = mock.Mock()
self._driver._setup_via_manager(gmgr, gmgr_parent)
ret = self._driver._setup_via_manager(
{'manager': gmgr, 'share': share},
{'manager': gmgr_parent, 'share': share_parent})
gmgr_parent.get_gluster_vol_option.assert_called_once_with(
'auth.ssl-allow')
@ -136,27 +145,33 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
('volume', 'set', 'fakevol', 'server.ssl', 'on'),
('volume', 'start', 'fakevol'))
gmgr.gluster_call.assert_has_calls([mock.call(*a) for a in args])
self.assertEqual(ret, gmgr.export)
@ddt.data(True, False)
def test_setup_via_manager_no_option_data(self, has_parent):
share = mock.Mock()
gmgr = mock.Mock()
if has_parent:
share_parent = mock.Mock()
gmgr_parent = mock.Mock()
share_mgr_parent = {'share': share_parent, 'manager': gmgr_parent}
gmgr_queried = gmgr_parent
else:
gmgr_parent = None
share_mgr_parent = None
gmgr_queried = gmgr
gmgr_queried.get_gluster_vol_option = mock.Mock(return_value='')
self.assertRaises(exception.GlusterfsException,
self._driver._setup_via_manager,
gmgr, gluster_mgr_parent=gmgr_parent)
{'share': share, 'manager': gmgr},
share_mgr_parent=share_mgr_parent)
gmgr_queried.get_gluster_vol_option.assert_called_once_with(
'auth.ssl-allow')
@ddt.data(exception.ProcessExecutionError, RuntimeError)
def test_setup_via_manager_exception(self, _exception):
share = mock.Mock()
gmgr = mock.Mock()
gmgr.gluster_call = mock.Mock(side_effect=_exception)
gmgr.get_gluster_vol_option = mock.Mock()
@ -164,7 +179,8 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
self.assertRaises(
{exception.ProcessExecutionError:
exception.GlusterfsException}.get(
_exception, _exception), self._driver._setup_via_manager, gmgr)
_exception, _exception), self._driver._setup_via_manager,
{'share': share, 'manager': gmgr})
def test_snapshots_are_supported(self):
self.assertTrue(self._driver.snapshots_are_supported)