X-Git-Url: http://xvm.mit.edu/gitweb/invirt/packages/invirt-console.git/blobdiff_plain/b78f64c598c8db7c0106f25a3bd2ad83e7d4ce45..66429809208491c7cc08a847471a3b86d71e9ff1:/files/usr/bin/sipb-xen-consolefs diff --git a/files/usr/bin/sipb-xen-consolefs b/files/usr/bin/sipb-xen-consolefs index 7cd3766..aa7d1ca 100755 --- a/files/usr/bin/sipb-xen-consolefs +++ b/files/usr/bin/sipb-xen-consolefs @@ -1,143 +1,92 @@ #!/usr/bin/python -import fuse -from fuse import Fuse +import routefs +from routes import Mapper +from syslog import * from time import time -import stat # for file properties -import os # for filesystem modes (O_RDONLY, etc) -import errno # for error number codes (ENOENT, etc) - # - note: these must be returned as negatives +import os +import errno -fuse.fuse_python_api = (0, 2) +from invirt.config import structs as config +from invirt import database -machines = ['moo17', 'remus'] realpath = "/home/machines/" -uid = 1000 -def dirFromList(list): +class ConsoleFS(routefs.RouteFS): """ - Return a properly formatted list of items suitable to a directory listing. - ['a', 'b', 'c'] => [('a', 0), ('b', 0), ('c', 0)] + ConsoleFS creates a series of subdirectories each mirroring the same real + directory, except for a single file - the .k5login - which is dynamically + generated for each subdirectory """ - return [(x, 0) for x in list] - -def getDepth(path): - """ - Return the depth of a given path, zero-based from root ('/') - """ - if path == '/': - return 0 - else: - return path.count('/') - -def getParts(path): - """ - Return the slash-separated parts of a given path as a list - """ - if path == '/': - return ['/'] - else: - return path[1:].split('/') - -class MyStat: - def __init__(self): - self.st_mode = 0 - self.st_ino = 0 - self.st_dev = 0 - self.st_nlink = 0 - self.st_uid = uid - self.st_gid = 0 - self.st_size = 0 - self.st_atime = 0 - self.st_mtime = 0 - self.st_ctime = 0 - def toTuple(self): - return (self.st_mode, self.st_ino, self.st_dev, self.st_nlink, self.st_uid, self.st_gid, self.st_size, self.st_atime, self.st_mtime, self.st_ctime) + def __init__(self, *args, **kw): + """Initialize the filesystem and set it to allow_other access besides + the user who mounts the filesystem (i.e. root) + """ + super(ConsoleFS, self).__init__(*args, **kw) + self.lasttime = time() + self.fuse_args.add("allow_other", True) + + openlog('sipb-xen-consolefs ', LOG_PID, LOG_DAEMON) + + syslog(LOG_DEBUG, 'Init complete.') -class ConsoleFS(Fuse): - """ - """ + def make_map(self): + m = Mapper() + m.connect('', controller='getMachines') + m.connect(':machine', controller='getMirror') + m.connect(':machine/.k5login', controller='getK5login') + m.connect(':machine/*(path)', controller='getMirror') + return m - def __init__(self, *args, **kw): - Fuse.__init__(self, *args, **kw) - print 'Init complete.' + def getMachines(self, **kw): + """Get the list of VMs in the database, clearing the cache if it's + older than 15 seconds""" + if time() - self.lasttime > 15: + self.lasttime = time() + database.clear_cache() + return [machine.name for machine in database.Machine.query()] + + def getMirror(self, machine, path='', **kw): + """Translate the path into its realpath equivalent, and return that + """ + real = realpath + path + if os.path.isdir(real): + # The list is converted to a set so that we can handle the case + # where there is already a .k5login in the realpath gracefully + return routefs.Directory(set(os.listdir(real) + ['.k5login'])) + elif os.path.islink(real): + return routefs.Symlink(os.readlink(real)) + elif os.path.isfile(real): + return open(real).read() + else: + return -errno.EINVAL + + def getK5login(self, machine, **kw): + """Build the ACL for a machine and turn it into a .k5login file + """ + machine = database.Machine.query().filter_by(name=machine).one() + users = [acl.user for acl in machine.acl] + return "\n".join(map(self.userToPrinc, users) + ['']) def mirrorPath(self, path): + """Translate a virtual path to its real path counterpart""" return realpath + "/".join(getParts(path)[1:]) - def getattr(self, path): - """ - - st_mode (protection bits) - - st_ino (inode number) - - st_dev (device) - - st_nlink (number of hard links) - - st_uid (user ID of owner) - - st_gid (group ID of owner) - - st_size (size of file, in bytes) - - st_atime (time of most recent access) - - st_mtime (time of most recent content modification) - - st_ctime (platform dependent; time of most recent metadata change on Unix, - or the time of creation on Windows). + def userToPrinc(self, user): + """Convert Kerberos v4-style names to v5-style and append a default + realm if none is specified """ - - print "*** getattr: " + path - - depth = getDepth(path) - parts = getParts(path) - - st = MyStat() - if path == '/': - st.st_mode = stat.S_IFDIR | 0755 - st.st_nlink = 2 - elif depth == 1: - if parts[-1] in machines: - st.st_mode = stat.S_IFDIR | 0755 - st.st_nlink = 2 - else: - return -errno.ENOENT - elif depth == 2 and parts[-1] == '.k5login': - st.st_mode = stat.S_IFREG | 0444 - st.st_nlink = 1 - st.st_size = 17 - else: - st = os.lstat(self.mirrorPath(path)) - return st.toTuple() - - def readdir(self, path, offset): - print '*** readdir', path, offset - if path == '/': - for r in ['.', '..']+machines: - yield fuse.Direntry(r) - elif getDepth(path) == 1: - for r in set(os.listdir(self.mirrorPath(path)) + ['.k5login']): - yield fuse.Direntry(r) + if '@' in user: + (princ, realm) = user.split('@') else: - for r in os.listdir(self.mirrorPath(path)): - yield fuse.Direntry(r) - - def read ( self, path, length, offset ): - print '*** read', path, length, offset + princ = user + realm = config.authn[0].realm - if getDepth(path) < 2: - return -errno.ENOENT - elif getParts(path)[1:] == ['.k5login']: - pass - else: - fname = self.mirrorPath(path) - if not os.path.isfile(fname): - return -errno.ENOENT - else: - f = open(fname) - f.seek(offset) - return f.read(length) + return princ.replace('.', '/') + '@' + realm if __name__ == '__main__': - usage=""" -ConsoleFS [mount_path] -""" - server = ConsoleFS() - server.flags = 0 - server.main() + database.connect() + routefs.main(ConsoleFS)