From 1266c51e57b32fd979a61ebfc73f93964223822f Mon Sep 17 00:00:00 2001 From: Prashanth Pai Date: Tue, 31 Jul 2018 15:22:04 +0530 Subject: Support setting multiple hosts (volfile servers) Fixes https://github.com/gluster/libgfapi-python/issues/20 Change-Id: If12dfb3166d37071f8996c4d043950aeb27d0ae7 Signed-off-by: Prashanth Pai --- gluster/gfapi/gfapi.py | 40 +++++++++++++++++++------------- test/functional/libgfapi-python-tests.py | 2 +- test/unit/gluster/test_gfapi.py | 14 +++++++++-- 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/gluster/gfapi/gfapi.py b/gluster/gfapi/gfapi.py index ee1fd36..f0aa4f8 100644 --- a/gluster/gfapi/gfapi.py +++ b/gluster/gfapi/gfapi.py @@ -672,13 +672,14 @@ class DirEntry(object): class Volume(object): - def __init__(self, host, volname, + def __init__(self, hosts, volname, proto="tcp", port=24007, log_file="/dev/null", log_level=7): """ Create a Volume object instance. - :param host: Host with glusterd management daemon running OR - : path to socket file which glusterd is listening on. + :param hosts: Host (string) or hosts (list of strings) with glusterd + daemon running OR path to socket file which glusterd is + listening on. :param volname: Name of GlusterFS volume to be mounted and used. :param proto: Transport protocol to be used to connect to management daemon. Permitted values are "tcp" and "rdma". @@ -704,15 +705,20 @@ class Volume(object): self.log_file = log_file self.log_level = log_level - if None in (volname, host): - # TODO: Validate host based on regex for IP/FQDN. + if None in (volname, hosts): raise LibgfapiException("Host and Volume name should not be None.") if proto not in ('tcp', 'rdma', 'unix'): raise LibgfapiException("Invalid protocol specified.") if not isinstance(port, int): raise LibgfapiException("Invalid port specified.") - self.host = host + if type(hosts) is not list: + hosts = [hosts] + + if len(hosts) < 1: + raise LibgfapiException("At least one host must be specified") + + self.hosts = hosts self.volname = volname self.volid = None self.protocol = proto @@ -743,16 +749,18 @@ class Volume(object): raise LibgfapiException("glfs_new(%s) failed: %s" % (self.volname, os.strerror(err))) - ret = api.glfs_set_volfile_server(self.fs, - decode_to_bytes(self.protocol), - decode_to_bytes(self.host), - self.port) - if ret < 0: - err = ctypes.get_errno() - raise LibgfapiException("glfs_set_volfile_server(%s, %s, %s, " - "%s) failed: %s" % (self.fs, self.protocol, - self.host, self.port, - os.strerror(err))) + for host in self.hosts: + ret = api.glfs_set_volfile_server(self.fs, + decode_to_bytes(self.protocol), + decode_to_bytes(host), + self.port) + if ret < 0: + err = ctypes.get_errno() + raise LibgfapiException("glfs_set_volfile_server(%s, %s, %s, " + "%s) failed: %s" % (self.fs, + self.protocol, + host, self.port, + os.strerror(err))) self.set_logging(self.log_file, self.log_level) diff --git a/test/functional/libgfapi-python-tests.py b/test/functional/libgfapi-python-tests.py index a699d8c..f6cc0fb 100644 --- a/test/functional/libgfapi-python-tests.py +++ b/test/functional/libgfapi-python-tests.py @@ -1120,7 +1120,7 @@ class TestVolumeInit(unittest.TestCase): # Check attribute init self.assertEqual(vol.log_file, "/dev/null") self.assertEqual(vol.log_level, 7) - self.assertEqual(vol.host, HOST) + self.assertEqual(vol.hosts[0], HOST) self.assertEqual(vol.volname, VOLNAME) self.assertEqual(vol.port, 24007) self.assertFalse(vol.mounted) diff --git a/test/unit/gluster/test_gfapi.py b/test/unit/gluster/test_gfapi.py index a8c0035..68d96a6 100644 --- a/test/unit/gluster/test_gfapi.py +++ b/test/unit/gluster/test_gfapi.py @@ -361,6 +361,7 @@ class TestVolume(unittest.TestCase): def test_initialization_error(self): self.assertRaises(LibgfapiException, Volume, "host", None) self.assertRaises(LibgfapiException, Volume, None, "vol") + self.assertRaises(LibgfapiException, Volume, [], "vol") self.assertRaises(LibgfapiException, Volume, None, None) self.assertRaises(LibgfapiException, Volume, "host", "vol", "ZZ") self.assertRaises(LibgfapiException, Volume, "host", "vol", @@ -368,7 +369,7 @@ class TestVolume(unittest.TestCase): def test_initialization_success(self): v = Volume("host", "vol", "tcp", 9876) - self.assertEqual(v.host, "host") + self.assertEqual(v.hosts[0], "host") self.assertEqual(v.volname, "vol") self.assertEqual(v.protocol, "tcp") self.assertEqual(v.port, 9876) @@ -414,7 +415,7 @@ class TestVolume(unittest.TestCase): self.assertFalse(v.mounted) _m_glfs_new.assert_called_once_with(b"vol") _m_set_vol.assert_called_once_with(v.fs, v.protocol.encode('utf-8'), - v.host.encode('utf-8'), v.port) + v.hosts[0].encode('utf-8'), v.port) # glfs_init() failed _m_glfs_init = Mock(return_value=-1) @@ -424,6 +425,15 @@ class TestVolume(unittest.TestCase): self.assertFalse(v.mounted) _m_glfs_init.assert_called_once_with(v.fs) + def test_mount_multiple_hosts(self): + _m_set_vol = Mock(return_value=0) + with patch("gluster.gfapi.api.glfs_set_volfile_server", _m_set_vol): + hosts = ["host1", "host2"] + v = Volume(hosts, "vol") + v.mount() + self.assertEqual(_m_set_vol.call_count, len(hosts)) + v.umount() + def test_umount_error(self): v = Volume("host", "vol") v.mount() -- cgit