#!/usr/bin/python import routefs from routes import Mapper from syslog import * from time import time import os import errno from invirt.config import structs as config from invirt import database realpath = "/home/machines/" class ConsoleFS(routefs.RouteFS): """ 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 """ 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 = 0 self.machines = [] self.fuse_args.add("allow_other", True) openlog('invirt-consolefs ', LOG_PID, LOG_DAEMON) syslog(LOG_DEBUG, 'Init complete.') 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 recache(self): if time() - self.lasttime > 5: self.lasttime = time() database.clear_cache() self.machines = dict((machine.name, machine) for machine in database.session.query(database.Machine).all()) def getMachines(self, **kw): self.recache() return self.machines.keys() 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): self.recache() machine = self.machines[machine] 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 userToPrinc(self, user): """Convert Kerberos v4-style names to v5-style and append a default realm if none is specified """ if '@' in user: (princ, realm) = user.split('@') else: princ = user realm = config.authn[0].realm return princ.replace('.', '/') + '@' + realm if __name__ == '__main__': database.connect() routefs.main(ConsoleFS)