diff options
-rwxr-xr-x | glusterfs/api.py | 149 | ||||
-rwxr-xr-x | glusterfs/gfapi.py | 35 | ||||
-rw-r--r-- | test/unit/gluster/test_gfapi.py | 42 |
3 files changed, 222 insertions, 4 deletions
diff --git a/glusterfs/api.py b/glusterfs/api.py index 1ecc34a..803a778 100755 --- a/glusterfs/api.py +++ b/glusterfs/api.py @@ -86,6 +86,149 @@ class Dirent (ctypes.Structure): ("d_name", ctypes.c_char * 256), ] + +# Here is the reference card of libgfapi library exported +# apis with its different versions. +# +# GFAPI_3.4.0 { +# glfs_new; +# glfs_set_volfile; +# glfs_set_volfile_server; +# glfs_set_logging; +# glfs_init; +# glfs_fini; +# glfs_open; +# glfs_creat; +# glfs_close; +# glfs_from_glfd; +# glfs_set_xlator_option; +# glfs_read; +# glfs_write; +# glfs_read_async; +# glfs_write_async; +# glfs_readv; +# glfs_writev; +# glfs_readv_async; +# glfs_writev_async; +# glfs_pread; +# glfs_pwrite; +# glfs_pread_async; +# glfs_pwrite_async; +# glfs_preadv; +# glfs_pwritev; +# glfs_preadv_async; +# glfs_pwritev_async; +# glfs_lseek; +# glfs_truncate; +# glfs_ftruncate; +# glfs_ftruncate_async; +# glfs_lstat; +# glfs_stat; +# glfs_fstat; +# glfs_fsync; +# glfs_fsync_async; +# glfs_fdatasync; +# glfs_fdatasync_async; +# glfs_access; +# glfs_symlink; +# glfs_readlink; +# glfs_mknod; +# glfs_mkdir; +# glfs_unlink; +# glfs_rmdir; +# glfs_rename; +# glfs_link; +# glfs_opendir; +# glfs_readdir_r; +# glfs_readdirplus_r; +# glfs_telldir; +# glfs_seekdir; +# glfs_closedir; +# glfs_statvfs; +# glfs_chmod; +# glfs_fchmod; +# glfs_chown; +# glfs_lchown; +# glfs_fchown; +# glfs_utimens; +# glfs_lutimens; +# glfs_futimens; +# glfs_getxattr; +# glfs_lgetxattr; +# glfs_fgetxattr; +# glfs_listxattr; +# glfs_llistxattr; +# glfs_flistxattr; +# glfs_setxattr; +# glfs_lsetxattr; +# glfs_fsetxattr; +# glfs_removexattr; +# glfs_lremovexattr; +# glfs_fremovexattr; +# glfs_getcwd; +# glfs_chdir; +# glfs_fchdir; +# glfs_realpath; +# glfs_posix_lock; +# glfs_dup; +# +# } +# +# GFAPI_3.4.2 { +# glfs_setfsuid; +# glfs_setfsgid; +# glfs_setfsgroups; +# glfs_h_lookupat; +# glfs_h_creat; +# glfs_h_mkdir; +# glfs_h_mknod; +# glfs_h_symlink; +# glfs_h_unlink; +# glfs_h_close; +# glfs_h_truncate; +# glfs_h_stat; +# glfs_h_getattrs; +# glfs_h_setattrs; +# glfs_h_readlink; +# glfs_h_link; +# glfs_h_rename; +# glfs_h_extract_handle; +# glfs_h_create_from_handle; +# glfs_h_opendir; +# glfs_h_open; +# } +# +# GFAPI_3.5.0 { +# +# glfs_get_volumeid; +# glfs_readdir; +# glfs_readdirplus; +# glfs_fallocate; +# glfs_discard; +# glfs_discard_async; +# glfs_zerofill; +# glfs_zerofill_async; +# glfs_caller_specific_init; +# glfs_h_setxattrs; +# +# } +# +# GFAPI_3.5.1 { +# +# glfs_unset_volfile_server; +# glfs_h_getxattrs; +# glfs_h_removexattrs; +# +# } +# +# GFAPI_3.6.0 { +# +# glfs_get_volfile; +# glfs_h_access; +# +# } +# + # Define function prototypes for the wrapper functions. glfs_init = ctypes.CFUNCTYPE( @@ -232,6 +375,12 @@ glfs_rmdir = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.c_char_p)(('glfs_rmdir', client)) +glfs_setfsuid = ctypes.CFUNCTYPE(ctypes.c_int, + ctypes.c_uint)(('glfs_setfsuid', client)) + +glfs_setfsgid = ctypes.CFUNCTYPE(ctypes.c_int, + ctypes.c_uint)(('glfs_setfsgid', client)) + # TODO: creat and open fails on test_create_file_already_exists & test_open_file_not_exist functional testing, # noqa # when defined via function prototype.. Need to find RCA. For time being, using it from 'api.glfs_' # noqa diff --git a/glusterfs/gfapi.py b/glusterfs/gfapi.py index 2d51a96..42c4aef 100755 --- a/glusterfs/gfapi.py +++ b/glusterfs/gfapi.py @@ -104,6 +104,12 @@ class File(object): raise OSError(err, os.strerror(err)) return ret + def fgetsize(self): + """ + Return the size of a file, reported by fstat() + """ + return self.fstat().st_size + def fstat(self): """ Returns Stat object for this file. @@ -137,9 +143,18 @@ class File(object): """ return api.glfs_lseek(self.fd, pos, how) - def read(self, buflen, flags=0): + def read(self, buflen=-1): + """ + read file + + :param buflen: length of read buffer. If less than 0, then whole + file is read. Default is -1. + :returns: buffer of size buflen + """ + if buflen < 0: + buflen = self.fgetsize() rbuf = ctypes.create_string_buffer(buflen) - ret = api.glfs_read(self.fd, rbuf, buflen, flags) + ret = api.glfs_read(self.fd, rbuf, buflen, 0) if ret > 0: return rbuf elif ret < 0: @@ -190,8 +205,6 @@ class Dir(object): class Volume(object): - # Housekeeping functions. - def __init__(self, host, volid, proto="tcp", port=24007): # Add a reference so the module-level variable "api" doesn't # get yanked out from under us (see comment above File def'n). @@ -468,6 +481,20 @@ class Volume(object): except OSError as e: onerror(self.rmdir, path, e) + def setfsuid(self, uid): + ret = api.glfs_setfsuid(uid) + if ret < 0: + err = ctypes.get_errno() + raise OSError(err, os.strerror(err)) + return ret + + def setfsgid(self, gid): + ret = api.glfs_setfsgid(gid) + if ret < 0: + err = ctypes.get_errno() + raise OSError(err, os.strerror(err)) + return ret + def setxattr(self, path, key, value, vlen): ret = api.glfs_setxattr(self.fs, path, key, value, vlen, 0) if ret < 0: diff --git a/test/unit/gluster/test_gfapi.py b/test/unit/gluster/test_gfapi.py index 1608332..8451b51 100644 --- a/test/unit/gluster/test_gfapi.py +++ b/test/unit/gluster/test_gfapi.py @@ -180,6 +180,18 @@ class TestFile(unittest.TestCase): b = self.fd.read(5) self.assertEqual(b, 0) + def test_read_buflen_negative(self): + _mock_fgetsize = Mock(return_value=12345) + + def _mock_glfs_read(fd, rbuf, buflen, flags): + self.assertEqual(buflen, 12345) + return buflen + + for buflen in (-1,-2,-999): + with patch("glusterfs.gfapi.api.glfs_read", _mock_glfs_read): + with patch("glusterfs.gfapi.File.fgetsize", _mock_fgetsize): + b = self.fd.read(buflen) + def test_write_success(self): mock_glfs_write = Mock() mock_glfs_write.return_value = 5 @@ -791,6 +803,36 @@ class TestVolume(unittest.TestCase): mock_unlink.assert_called_once_with("dir1/file") mock_rmdir.assert_called_with("dir1") + def test_setfsuid_success(self): + mock_glfs_setfsuid = Mock() + mock_glfs_setfsuid.return_value = 0 + + with patch("glusterfs.gfapi.api.glfs_setfsuid", mock_glfs_setfsuid): + ret = self.vol.setfsuid(1000) + self.assertEquals(ret, 0) + + def test_setfsuid_fail(self): + mock_glfs_setfsuid = Mock() + mock_glfs_setfsuid.return_value = -1 + + with patch("glusterfs.gfapi.api.glfs_setfsuid", mock_glfs_setfsuid): + self.assertRaises(OSError, self.vol.setfsuid, 1001) + + def test_setfsgid_success(self): + mock_glfs_setfsgid = Mock() + mock_glfs_setfsgid.return_value = 0 + + with patch("glusterfs.gfapi.api.glfs_setfsgid", mock_glfs_setfsgid): + ret = self.vol.setfsgid(1000) + self.assertEquals(ret, 0) + + def test_setfsgid_fail(self): + mock_glfs_setfsgid = Mock() + mock_glfs_setfsgid.return_value = -1 + + with patch("glusterfs.gfapi.api.glfs_setfsgid", mock_glfs_setfsgid): + self.assertRaises(OSError, self.vol.setfsgid, 1001) + def test_setxattr_success(self): mock_glfs_setxattr = Mock() mock_glfs_setxattr.return_value = 0 |