glusterfs: add NFS-Ganesha based service backend
Partially implements blueprint gateway-mediated-with-ganesha Change-Id: I92da2117086ed25f304e8da9db7ca8c686c6463c
This commit is contained in:
parent
e4dac43a5f
commit
d3b499b9ac
@ -55,7 +55,7 @@ GlusterfsManilaShare_opts = [
|
||||
cfg.StrOpt('glusterfs_nfs_server_type',
|
||||
default='Gluster',
|
||||
help='Type of NFS server that mediate access to the Gluster '
|
||||
'volumes (for now: only Gluster).'),
|
||||
'volumes (Gluster or Ganesha).'),
|
||||
cfg.StrOpt('glusterfs_server_password',
|
||||
default=None,
|
||||
secret=True,
|
||||
@ -65,6 +65,18 @@ GlusterfsManilaShare_opts = [
|
||||
cfg.StrOpt('glusterfs_path_to_private_key',
|
||||
default=None,
|
||||
help='Path of Manila host\'s private SSH key file.'),
|
||||
cfg.StrOpt('glusterfs_ganesha_server_ip',
|
||||
default=None,
|
||||
help="Remote Ganesha server node's IP address."),
|
||||
cfg.StrOpt('glusterfs_ganesha_server_username',
|
||||
default='root',
|
||||
help="Remote Ganesha server node's username."),
|
||||
cfg.StrOpt('glusterfs_ganesha_server_password',
|
||||
default=None,
|
||||
secret=True,
|
||||
help="Remote Ganesha server node's login password. "
|
||||
"This is not required if 'glusterfs_path_to_private_key'"
|
||||
' is configured.'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -463,3 +475,32 @@ class GlusterNFSHelper(ganesha.NASHelperBase):
|
||||
ddict.pop(edir)
|
||||
self._manage_access(share['name'], access['access_type'],
|
||||
access['access_to'], cbk)
|
||||
|
||||
|
||||
class GaneshaNFSHelper(ganesha.GaneshaNASHelper):
|
||||
|
||||
def __init__(self, execute, config_object, **kwargs):
|
||||
self.gluster_manager = kwargs.pop('gluster_manager')
|
||||
if config_object.glusterfs_ganesha_server_ip:
|
||||
execute = ganesha_utils.SSHExecutor(
|
||||
config_object.glusterfs_ganesha_server_ip, 22, None,
|
||||
config_object.glusterfs_ganesha_server_username,
|
||||
password=config_object.glusterfs_ganesha_server_password,
|
||||
privatekey=config_object.glusterfs_path_to_private_key)
|
||||
else:
|
||||
execute = ganesha_utils.RootExecutor(execute)
|
||||
super(GaneshaNFSHelper, self).__init__(execute, config_object,
|
||||
**kwargs)
|
||||
|
||||
def _default_config_hook(self):
|
||||
"""Callback to provide default export block."""
|
||||
dconf = super(GaneshaNFSHelper, self)._default_config_hook()
|
||||
conf_dir = ganesha_utils.path_from(__file__, "glusterfs", "conf")
|
||||
ganesha_utils.patch(dconf, self._load_conf_dir(conf_dir))
|
||||
return dconf
|
||||
|
||||
def _fsal_hook(self, base, share, access):
|
||||
"""Callback to create FSAL subblock."""
|
||||
return {"Hostname": self.gluster_manager.host,
|
||||
"Volume": self.gluster_manager.volume,
|
||||
"Volpath": "/" + share['name']}
|
||||
|
@ -0,0 +1,8 @@
|
||||
EXPORT {
|
||||
FSAL {
|
||||
Name = GLUSTER;
|
||||
Hostname = @config;
|
||||
Volume = @config;
|
||||
Volpath = @runtime;
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
import errno
|
||||
import os
|
||||
|
||||
@ -43,7 +44,6 @@ fake_gluster_manager_attrs = {
|
||||
|
||||
fake_local_share_path = '/mnt/nfs/testvol/fakename'
|
||||
|
||||
|
||||
fake_args = ('foo', 'bar')
|
||||
fake_kwargs = {'key1': 'value1', 'key2': 'value2'}
|
||||
fake_path_to_private_key = '/fakepath/to/privatekey'
|
||||
@ -844,3 +844,81 @@ class GlusterNFSHelperTestCase(test.TestCase):
|
||||
self._helper._get_export_dir_dict.assert_called_once_with()
|
||||
self._helper.gluster_manager.gluster_call.assert_called_once_with(
|
||||
*args)
|
||||
|
||||
|
||||
class GaneshaNFSHelperTestCase(test.TestCase):
|
||||
"""Tests GaneshaNFSHelper."""
|
||||
|
||||
def setUp(self):
|
||||
super(GaneshaNFSHelperTestCase, self).setUp()
|
||||
self.gluster_manager = mock.Mock(**fake_gluster_manager_attrs)
|
||||
self._execute = mock.Mock(return_value=('', ''))
|
||||
self._root_execute = mock.Mock(return_value=('', ''))
|
||||
self.access = fake_share.fake_access()
|
||||
self.fake_conf = config.Configuration(None)
|
||||
self.fake_template = {'key': 'value'}
|
||||
self.share = fake_share.fake_share()
|
||||
self.mock_object(glusterfs.ganesha_utils, 'RootExecutor',
|
||||
mock.Mock(return_value=self._root_execute))
|
||||
self.mock_object(glusterfs.ganesha.GaneshaNASHelper, '__init__',
|
||||
mock.Mock())
|
||||
self._helper = glusterfs.GaneshaNFSHelper(
|
||||
self._execute, self.fake_conf,
|
||||
gluster_manager=self.gluster_manager)
|
||||
|
||||
def test_init_local_ganesha_server(self):
|
||||
glusterfs.ganesha_utils.RootExecutor.assert_called_once_with(
|
||||
self._execute)
|
||||
glusterfs.ganesha.GaneshaNASHelper.__init__.assert_has_calls(
|
||||
[mock.call(self._root_execute, self.fake_conf)])
|
||||
|
||||
def test_init_remote_ganesha_server(self):
|
||||
ssh_execute = mock.Mock(return_value=('', ''))
|
||||
CONF.set_default('glusterfs_ganesha_server_ip', 'fakeip')
|
||||
self.mock_object(glusterfs.ganesha_utils, 'SSHExecutor',
|
||||
mock.Mock(return_value=ssh_execute))
|
||||
glusterfs.GaneshaNFSHelper(
|
||||
self._execute, self.fake_conf,
|
||||
gluster_manager=self.gluster_manager)
|
||||
glusterfs.ganesha_utils.SSHExecutor.assert_called_once_with(
|
||||
'fakeip', 22, None, 'root', password=None, privatekey=None)
|
||||
glusterfs.ganesha.GaneshaNASHelper.__init__.assert_has_calls(
|
||||
[mock.call(ssh_execute, self.fake_conf)])
|
||||
|
||||
def test_default_config_hook(self):
|
||||
fake_conf_dict = {'key': 'value1'}
|
||||
mock_ganesha_utils_patch = mock.Mock()
|
||||
|
||||
def fake_patch_run(tmpl1, tmpl2):
|
||||
mock_ganesha_utils_patch(
|
||||
copy.deepcopy(tmpl1), tmpl2)
|
||||
tmpl1.update(tmpl2)
|
||||
|
||||
self.mock_object(glusterfs.ganesha.GaneshaNASHelper,
|
||||
'_default_config_hook',
|
||||
mock.Mock(return_value=self.fake_template))
|
||||
self.mock_object(glusterfs.ganesha_utils, 'path_from',
|
||||
mock.Mock(return_value='/fakedir/glusterfs/conf'))
|
||||
self.mock_object(self._helper, '_load_conf_dir',
|
||||
mock.Mock(return_value=fake_conf_dict))
|
||||
self.mock_object(glusterfs.ganesha_utils, 'patch',
|
||||
mock.Mock(side_effect=fake_patch_run))
|
||||
ret = self._helper._default_config_hook()
|
||||
glusterfs.ganesha.GaneshaNASHelper._default_config_hook.\
|
||||
assert_called_once_with()
|
||||
glusterfs.ganesha_utils.path_from.assert_called_once_with(
|
||||
glusterfs.__file__, 'glusterfs', 'conf')
|
||||
self._helper._load_conf_dir.assert_called_once_with(
|
||||
'/fakedir/glusterfs/conf')
|
||||
glusterfs.ganesha_utils.patch.assert_called_once_with(
|
||||
self.fake_template, fake_conf_dict)
|
||||
self.assertEqual(fake_conf_dict, ret)
|
||||
|
||||
def test_fsal_hook(self):
|
||||
output = {
|
||||
'Hostname': '127.0.0.1',
|
||||
'Volume': 'testvol',
|
||||
'Volpath': '/fakename'
|
||||
}
|
||||
ret = self._helper._fsal_hook('/fakepath', self.share, self.access)
|
||||
self.assertEqual(output, ret)
|
||||
|
Loading…
Reference in New Issue
Block a user