#!/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 = time() 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 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 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)