diff options
Diffstat (limited to 'api/examples/gfapi.py')
-rwxr-xr-x | api/examples/gfapi.py | 422 |
1 files changed, 0 insertions, 422 deletions
diff --git a/api/examples/gfapi.py b/api/examples/gfapi.py deleted file mode 100755 index 3ac67f4d5ba..00000000000 --- a/api/examples/gfapi.py +++ /dev/null @@ -1,422 +0,0 @@ -#!/usr/bin/python - -from ctypes import * -from ctypes.util import find_library -import os -import sys -import time -import types - -# Looks like ctypes is having trouble with dependencies, so just force them to -# load with RTLD_GLOBAL until I figure that out. -glfs = CDLL(find_library("glusterfs"),RTLD_GLOBAL) -xdr = CDLL(find_library("gfxdr"),RTLD_GLOBAL) -api = CDLL(find_library("gfapi"),RTLD_GLOBAL) - -# Wow, the Linux kernel folks really play nasty games with this structure. If -# you look at the man page for stat(2) and then at this definition you'll note -# two discrepancies. First, we seem to have st_nlink and st_mode reversed. In -# fact that's exactly how they're defined *for 64-bit systems*; for 32-bit -# they're in the man-page order. Even uglier, the man page makes no mention of -# the *nsec fields, but they are very much present and if they're not included -# then we get memory corruption because libgfapi has a structure definition -# that's longer than ours and they overwrite some random bit of memory after -# the space we allocated. Yes, that's all very disgusting, and I'm still not -# sure this will really work on 32-bit because all of the field types are so -# obfuscated behind macros and feature checks. -class Stat (Structure): - _fields_ = [ - ("st_dev", c_ulong), - ("st_ino", c_ulong), - ("st_nlink", c_ulong), - ("st_mode", c_uint), - ("st_uid", c_uint), - ("st_gid", c_uint), - ("st_rdev", c_ulong), - ("st_size", c_ulong), - ("st_blksize", c_ulong), - ("st_blocks", c_ulong), - ("st_atime", c_ulong), - ("st_atimensec", c_ulong), - ("st_mtime", c_ulong), - ("st_mtimensec", c_ulong), - ("st_ctime", c_ulong), - ("st_ctimensec", c_ulong), - ] -api.glfs_creat.restype = c_void_p -api.glfs_open.restype = c_void_p -api.glfs_lstat.restype = c_int -api.glfs_lstat.argtypes = [c_void_p, c_char_p, POINTER(Stat)] - -class Dirent (Structure): - _fields_ = [ - ("d_ino", c_ulong), - ("d_off", c_ulong), - ("d_reclen", c_ushort), - ("d_type", c_char), - ("d_name", c_char * 256), - ] -api.glfs_opendir.restype = c_void_p -api.glfs_readdir_r.restype = c_int -api.glfs_readdir_r.argtypes = [c_void_p, POINTER(Dirent), - POINTER(POINTER(Dirent))] - -# There's a bit of ctypes glitchiness around __del__ functions and module-level -# variables. If we unload the module while we still have references to File or -# Volume objects, the module-level variables might have disappeared by the time -# __del__ gets called. Therefore the objects hold references which they -# release when __del__ is done. We only actually use the object-local values -# in __del__; for clarity, we just use the simpler module-level form elsewhere. - -class File(object): - - def __init__ (self, fd): - # Add a reference so the module-level variable "api" doesn't - # get yanked out from under us (see comment above File def'n). - self._api = api - self.fd = fd - - def __del__ (self): - self._api.glfs_close(self.fd) - self._api = None - - # File operations, in alphabetical order. - - def fsync (self): - return api.glfs_fsync(self.fd) - - def read (self, buflen, flags=0): - rbuf = create_string_buffer(buflen) - rc = api.glfs_read(self.fd,rbuf,buflen,flags) - if rc > 0: - return rbuf.value[:rc] - else: - return rc - - def read_buffer (self, buf, flags=0): - return api.glfs_read(self.fd,buf,len(buf),flags) - - def write (self, data, flags=0): - return api.glfs_write(self.fd,data,len(data),flags) - - def fallocate (self, mode, offset, len): - return api.glfs_fallocate(self.fd, mode, offset, len) - - def discard (self, offset, len): - return api.glfs_discard(self.fd, offset, len) - - -class Dir(object): - - def __init__ (self, fd): - # Add a reference so the module-level variable "api" doesn't - # get yanked out from under us (see comment above File def'n). - self._api = api - self.fd = fd - self.cursor = POINTER(Dirent)() - - def __del__ (self): - self._api.glfs_closedir(self.fd) - self._api = None - - def next (self): - entry = Dirent() - entry.d_reclen = 256 - rc = api.glfs_readdir_r(self.fd,byref(entry),byref(self.cursor)) - if (rc < 0) or (not self.cursor) or (not self.cursor.contents): - return rc - return entry - -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). - self._api = api - self.fs = api.glfs_new(volid) - api.glfs_set_volfile_server(self.fs,proto,host,port) - - def __del__ (self): - self._api.glfs_fini(self.fs) - self._api = None - - def set_logging (self, path, level): - api.glfs_set_logging(self.fs,path,level) - - def mount (self): - api.glfs_init(self.fs) - - # File operations, in alphabetical order. - - def creat (self, path, flags, mode): - fd = api.glfs_creat(self.fs,path,flags,mode) - if not fd: - return fd - return File(fd) - - def getxattr (self, path, key, maxlen): - buf = create_string_buffer(maxlen) - rc = api.glfs_getxattr(self.fs,path,key,buf,maxlen) - if rc < 0: - return rc - return buf.value[:rc] - - def listxattr (self, path): - buf = create_string_buffer(512) - rc = api.glfs_listxattr(self.fs,path,buf,512) - if rc < 0: - return rc - xattrs = [] - # Parsing character by character is ugly, but it seems like the - # easiest way to deal with the "strings separated by NUL in one - # buffer" format. - i = 0 - while i < rc: - new_xa = buf.raw[i] - i += 1 - while i < rc: - next_char = buf.raw[i] - i += 1 - if next_char == '\0': - xattrs.append(new_xa) - break - new_xa += next_char - xattrs.sort() - return xattrs - - def lstat (self, path): - x = Stat() - rc = api.glfs_lstat(self.fs,path,byref(x)) - if rc >= 0: - return x - else: - return rc - - def mkdir (self, path): - return api.glfs_mkdir(self.fs,path) - - def open (self, path, flags): - fd = api.glfs_open(self.fs,path,flags) - if not fd: - return fd - return File(fd) - - def opendir (self, path): - fd = api.glfs_opendir(self.fs,path) - if not fd: - return fd - return Dir(fd) - - def rename (self, opath, npath): - return api.glfs_rename(self.fs,opath,npath) - - def rmdir (self, path): - return api.glfs_rmdir(self.fs,path) - - def setxattr (self, path, key, value, vlen): - return api.glfs_setxattr(self.fs,path,key,value,vlen,0) - - def unlink (self, path): - return api.glfs_unlink(self.fs,path) - -if __name__ == "__main__": - def test_create_write (vol, path, data): - mypath = path + ".io" - fd = vol.creat(mypath,os.O_WRONLY|os.O_EXCL,0644) - if not fd: - return False, "creat error" - rc = fd.write(data) - if rc != len(data): - return False, "wrote %d/%d bytes" % (rc, len(data)) - return True, "wrote %d bytes" % rc - - # TBD: this test fails if we do create, open, write, read - def test_open_read (vol, path, data): - mypath = path + ".io" - fd = vol.open(mypath,os.O_RDONLY) - if not fd: - return False, "open error" - dlen = len(data) * 2 - buf = fd.read(dlen) - if type(buf) == types.IntType: - return False, "read error %d" % buf - if len(buf) != len(data): - return False, "read %d/%d bytes" % (len(buf), len(data)) - return True, "read '%s'" % buf - - def test_lstat (vol, path, data): - mypath = path + ".io" - sb = vol.lstat(mypath) - if type(sb) == types.IntType: - return False, "lstat error %d" % sb - if sb.st_size != len(data): - return False, "lstat size is %d, expected %d" % ( - sb.st_size, len(data)) - return True, "lstat got correct size %d" % sb.st_size - - def test_rename (vol, path, data): - opath = path + ".io" - npath = path + ".tmp" - rc = vol.rename(opath,npath) - if rc < 0: - return False, "rename error %d" % rc - ofd = vol.open(opath,os.O_RDWR) - if isinstance(ofd,File): - return False, "old path working after rename" - nfd = vol.open(npath,os.O_RDWR) - if isinstance(nfd,File): - return False, "new path not working after rename" - return True, "rename worked" - - def test_unlink (vol, path, data): - mypath = path + ".tmp" - rc = vol.unlink(mypath) - if rc < 0: - return False, "unlink error %d" % fd - fd = vol.open(mypath,os.O_RDWR) - if isinstance(fd,File): - return False, "path still usable after unlink" - return True, "unlink worked" - - def test_mkdir (vol, path, data): - mypath = path + ".dir" - rc = vol.mkdir(mypath) - if rc < 0: - return False, "mkdir error %d" % rc - return True, "mkdir worked" - - def test_create_in_dir (vol, path, data): - mypath = path + ".dir/probe" - fd = vol.creat(mypath,os.O_RDWR,0644) - if not isinstance(fd,File): - return False, "create (in dir) error" - return True, "create (in dir) worked" - - def test_dir_listing (vol, path, data): - mypath = path + ".dir" - fd = vol.opendir(mypath) - if not isinstance(fd,Dir): - return False, "opendir error %d" % fd - files = [] - while True: - ent = fd.next() - if not isinstance(ent,Dirent): - break - name = ent.d_name[:ent.d_reclen] - files.append(name) - if files != [".", "..", "probe"]: - return False, "wrong directory contents" - return True, "directory listing worked" - - def test_unlink_in_dir (vol, path, data): - mypath = path + ".dir/probe" - rc = vol.unlink(mypath) - if rc < 0: - return False, "unlink (in dir) error %d" % rc - return True, "unlink (in dir) worked" - - def test_rmdir (vol, path, data): - mypath = path + ".dir" - rc = vol.rmdir(mypath) - if rc < 0: - return False, "rmdir error %d" % rc - sb = vol.lstat(mypath) - if not isinstance(sb,Stat): - return False, "dir still there after rmdir" - return True, "rmdir worked" - - def test_setxattr (vol, path, data): - mypath = path + ".xa" - fd = vol.creat(mypath,os.O_RDWR|os.O_EXCL,0644) - if not fd: - return False, "creat (xattr test) error" - key1, key2 = "hello", "goodbye" - if vol.setxattr(mypath,"trusted.key1",key1,len(key1)) < 0: - return False, "setxattr (key1) error" - if vol.setxattr(mypath,"trusted.key2",key2,len(key2)) < 0: - return False, "setxattr (key2) error" - return True, "setxattr worked" - - def test_getxattr (vol, path, data): - mypath = path + ".xa" - buf = vol.getxattr(mypath,"trusted.key1",32) - if type(buf) == types.IntType: - return False, "getxattr error" - if buf != "hello": - return False, "wrong getxattr value %s" % buf - return True, "getxattr worked" - - def test_listxattr (vol, path, data): - mypath = path + ".xa" - xattrs = vol.listxattr(mypath) - if type(xattrs) == types.IntType: - return False, "listxattr error" - if xattrs != ["trusted.key1","trusted.key2"]: - return False, "wrong listxattr value %s" % repr(xattrs) - return True, "listxattr worked" - - def test_fallocate (vol, path, data): - mypath = path + ".io" - fd = vol.creat(mypath,os.O_WRONLY|os.O_EXCL,0644) - if not fd: - return False, "creat error" - rc = fd.fallocate(0, 0, 1024*1024) - if rc != 0: - return False, "fallocate error" - rc = fd.discard(4096, 4096) - if rc != 0: - return False, "discard error" - return True, "fallocate/discard worked" - - test_list = ( - test_create_write, - test_open_read, - test_lstat, - test_rename, - test_unlink, - test_mkdir, - test_create_in_dir, - test_dir_listing, - test_unlink_in_dir, - test_rmdir, - test_setxattr, - test_getxattr, - test_listxattr, - test_fallocate, - ) - - ok_to_fail = ( - # TBD: this fails opening the new file, even though the file - # did get renamed. Looks like a gfapi bug, not ours. - (test_rename, "new path not working after rename"), - # TBD: similar, call returns error even though it worked - (test_rmdir, "dir still there after rmdir"), - ) - - volid, path = sys.argv[1:3] - data = "fubar" - vol = Volume("localhost",volid) - vol.set_logging("/dev/null",7) - #vol.set_logging("/dev/stderr",7) - vol.mount() - - failures = 0 - expected = 0 - for t in test_list: - rc, msg = t(vol,path,data) - if rc: - print "PASS: %s" % msg - else: - print "FAIL: %s" % msg - failures += 1 - for otf in ok_to_fail: - if (t == otf[0]) and (msg == otf[1]): - print " (skipping known failure)" - expected += 1 - break # from the *inner* for loop - else: - break # from the *outer* for loop - - print "%d failures (%d expected)" % (failures, expected) |