def realpath(self, path): """Return the canonical version of path eliminating any symlinks encountered in the path this gets called by the FTPHander when: * A user does an 'ls' or 'dir' """ logger.debug("realpath(%s)" % path) return super(AbstractedQSFS, self).realpath(path)
def has_user(self, username): logger.debug("has_user(%s)" % username) local_rc = RestClient(API_HOST, API_PORT) local_rc.login(API_USER, API_PASS) response = local_rc.users.list_users() name_list = [user['name'] for user in response] return username in name_list
def mkstemp(self, suffix='', prefix='', directory=None, mode='wb'): logger.debug("mkstemp(suffix='%s', prefix='%s', dir='%s', mode='%s')" % (suffix, prefix, directory, mode)) return super(AbstractedQSFS, self).mkstemp(suffix='', prefix='', dir=None, mode='wb')
def get_msg_login(self, username): logger.debug("get_msg_login() returns the same message for everyone") admin_rc = get_rc() response = admin_rc.config.cluster_config_get() cluster_name = response[u'bootstrap'][u'cluster_name'] version = self.rc.version.version()['revision_id'] return u"Welcome to qftpd on %s (%s)" % (cluster_name, version)
def isfile(self, path): logger.debug("isfile(%s)" % path) response = self.rc.fs.get_attr(path=path) #return super(AbstractedQSFS, self).isfile(path) retval = response['type'] == u'FS_FILE_TYPE_FILE' logger.debug("isfile(%s) will return %s" % (path, retval)) return retval
def get_group_by_gid(self, gid): logger.debug("get_group_by_gid(%s)" % gid) try: response = self.rc.groups.list_group(gid)['name'] except RequestError: response = str(gid) logger.debug("get_group_by_gid returned " + str(response)) return response
def format_mlsx(self, basedir, listing, perms, facts, ignore_err=True): logger.debug("format_mlsx(%s, %s, %s, %s, %s)" % (basedir, listing, perms, facts, ignore_err)) return super(AbstractedQSFS, self).format_mlsx(basedir, listing, perms, facts, ignore_err)
def get_user_by_uid(self, uid): logger.debug("get_user_by_uid(%s)" % uid) try: response = self.rc.users.list_user(uid)['name'] except RequestError: response = str(uid) logger.debug("get_user_by_uid returned " + str(response)) return response
def impersonate_user(self, username, password): """This should probably return a RestClient assuming it gets called after login """ logger.debug("impersonate_user() returning RestClient") local_rc = RestClient(API_HOST, API_PORT) local_rc.login(username, password) return local_rc
def stat(self, path): """ [D 15-03-05 14:47:30] lstat(/Users/mbott/DESCRIPTION_TEST2.tsv) [D 15-03-05 14:47:30] lstat returned posix.stat_result(st_mode=33188, st_ino=6613236, st_dev=16777220L, st_nlink=1, st_uid=2090, st_gid=2000, st_size=181331, st_atime=1425167786, st_mtime=1424917246, st_ctime=1424917246) """ logger.debug("NOT IMPLEMENTED stat(%s)" % path) return super(AbstractedQSFS, self).stat(path)
def mkdir(self, path): logger.debug("mkdir(%s)" % path) # strip trailing slashes from the directory name path = path.rstrip('/') (path, name) = os.path.split(path) try: self.rc.fs.create_directory(name=name, dir_path=path) except RequestError, e: raise FilesystemError(str(e))
def close(self): """On close, seek to 0 and write the data via the API, then close() for realz """ logger.debug("close() called on WriteBuffer") self.seek(0) logger.debug("Attempting to create file at dir_path %s with name %s" % (self.path, self.filename)) self.fs.rc.fs.write_file(self, self.fullpath) SpooledTemporaryFile.close(self) # old-style class!
def read_file_handle(self, filename): """Get the file data, put it in a SpooledTemporaryFile object for return and reading """ logger.debug("read_file_handle('%s')" % filename) read_buffer = SpooledTemporaryFile() response = self.rc.fs.read_file(read_buffer, filename) logger.debug(response) read_buffer.seek(0) return read_buffer
def write_file_handle(self, filename): """This is trickier than the read, because we need a callback on close() to write the file to QSFS via RC """ logger.debug("write_file_handle('%s')" % filename) path = self.realpath(filename) (dirname, basename) = os.path.split(path) logger.debug("realpath() found %s" % path) write_buffer = WriteBuffer(dirname, basename, fs=self) return write_buffer
def chdir(self, path): """Change the current directory.""" # note: process cwd will be reset by the caller # note2: since QSFS is REST, we just track cwd state in the # AbstractedQSFS instance created by the FTPHandler logger.debug("chdir(%s)" % path) assert isinstance(path, unicode), path if not self.isdir(path): raise FilesystemError('%s is not a valid directory' % path) self._cwd = self.fs2ftp(path)
def validate_authentication(self, username, password, handler): """Attempt to login using RestClient, raise AuthenticationFailed if we don't login successfully """ logger.debug("validate_authentication(%s, %s, handler)" % (username, password)) # attempt login with restclient try: self.rc.login(username, password) except RequestError: raise AuthenticationFailed
def open(self, filename, mode): """Return a file handler for the filename and mode specified. This will need to get the file id from the Qumulo REST client and do something useful with it, depending on the mode passed in to this method. """ logger.debug("open(%s, %s)" % (filename, mode)) assert isinstance(filename, unicode), filename if 'r' in mode: # read files! return self.read_file_handle(filename) elif 'w' in mode: # write files! return self.write_file_handle(filename)
def isdir(self, path): logger.debug("isdir(%s)" % path) # if this path has "type": "FS_FILE_TYPE_DIRECTORY", return true try: response = self.rc.fs.get_attr(path=path) except RequestError as err: raise FilesystemError(err) #return super(AbstractedQSFS, self).isdir(path) logger.debug("isdir(%s) will return %s" % (path, response['type'] == 'FS_FILE_TYPE_DIRECTORY')) return response['type'] == u'FS_FILE_TYPE_DIRECTORY'
def rmdir(self, path): logger.debug("rmdir(%s)" % path) # make sure the path has one and only one trailing slash or this fails # in the RestClient path = path.rstrip('/') + '/' try: self.rc.fs.delete(path) except RequestError: # This can explode if we try to rmdir a file message = 'Ignoring rmdir(%s) because %s is not a dir' % \ (path, path) logger.warn(message) raise FilesystemError(message)
def run_as_current_user(self, function, *args, **kwargs): """Execute a function impersonating the current logged-in user. This needs to set up the restclient in the filesystem so it do its thing """ if not self.fs.rc: local_rc = self.authorizer.impersonate_user( self.username, self.password) logger.debug("local_rc: " + str(local_rc)) self.fs.set_rc(local_rc) try: return function(*args, **kwargs) finally: self.authorizer.terminate_impersonation(self.username)
def lstat(self, path): """This gets called on every file when a user is trying to 'ls' or 'dir' [D 15-03-05 14:47:30] lstat(/Users/mbott/DESCRIPTION_TEST2.tsv) [D 15-03-05 14:47:30] lstat returned posix.stat_result(st_mode=33188, st_ino=6613236, st_dev=16777220L, st_nlink=1, st_uid=2090, st_gid=2000, st_size=181331, st_atime=1425167786, st_mtime=1424917246, st_ctime=1424917246) Qumulo Get File Stat returns: { "change_time": "2015-03-05T02:01:53.498584694Z", "mode": "0777", "file_number": "2", "group": "513", "id": "2", "path": "/", "name": "", "num_links": 3, "child_count": 2, "blocks": "0", "type": "FS_FILE_TYPE_DIRECTORY", "owner": "500", "size": "1024", "modification_time": "2015-03-05T02:01:53.498584694Z", "creation_time": "2015-03-05T01:38:36.499327207Z" } """ logger.debug("lstat(%s)" % path) qstat = self.rc.fs.get_attr(path=path) stat_r = stat_result() setattr(stat_r, 'st_mode', self.get_st_mode(qstat)) setattr(stat_r, 'st_ino', self.get_st_ino(qstat)) setattr(stat_r, 'st_dev', self.get_st_dev()) # devno meaningless here setattr(stat_r, 'st_nlink', self.get_st_nlink(qstat)) setattr(stat_r, 'st_uid', self.get_st_uid(qstat)) setattr(stat_r, 'st_gid', self.get_st_gid(qstat)) setattr(stat_r, 'st_size', self.get_st_size(qstat)) setattr(stat_r, 'st_atime', self.get_st_atime(qstat)) setattr(stat_r, 'st_ctime', self.get_st_ctime(qstat)) setattr(stat_r, 'st_mtime', self.get_st_mtime(qstat)) return stat_r
def listdir(self, path): """list the contents of a directory path""" logger.debug("listdir(%s)" % path) assert isinstance(path, unicode), path # use the restclient to get the contents of a real path response = self.rc.fs.read_directory(page_size=1000, path=path) logger.debug(str(response)) dir_list = [f['name'] for f in response['files']] logger.debug("listdir() will return " + str(dir_list)) return dir_list
def _issubpath(self, a, b): logger.debug("NOT IMPLEMENTED _issubpath()") super(QSFSAuthorizer, self)._issubpath(a, b)
def _check_permissions(self, username, perm): logger.debug("NOT IMPLEMENTED _check_permissions()") super(QSFSAuthorizer, self)._check_permissions(username, perm)
def get_msg_quit(self, username): logger.debug("get_msg_quit() will return the same message for everyone") return u"Goodbye."
def get_home_dir(self, username): logger.debug("get_home_dir() will return '/' for all users") return u'/'
def get_perms(self, username): logger.debug("NOT IMPLEMENTED get_perms()") super(QSFSAuthorizer, self).get_perms(username)
def has_perm(self, username, perm, path=None): logger.debug("has_perm() will always return True") return True
def terminate_impersonation(self, username): """This should kill off the restclient created when impersonating the user """ logger.debug("terminate_impersonation() called, doing nothing")
def logline(msg): _depwarn("pyftpdlib.ftpserver.logline() is deprecated") logger.debug(msg)