#!/usr/bin/python

import routefs
from routes import Mapper

from syslog import *
from time import time

from invirt import database
from invirt.config import structs as config

class RemConfFS(routefs.RouteFS):
    """
    RemConfFS creates a filesytem for configuring remctl, like this:
    /
    |-- acl
    |   |-- machine1
    |   ...
    |   `-- machinen
    `-- conf
    
    The machine list and the acls are drawn from a database.
    """
    
    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(RemConfFS, self).__init__(*args, **kw)
        self.lasttime = 0
        self.fuse_args.add("allow_other", True)
        
        openlog('invirt-remconffs ', LOG_PID, LOG_DAEMON)
        
        syslog(LOG_DEBUG, 'Init complete.')
    
    def make_map(self):
        m = Mapper()
        m.connect('', controller='getroot')
        m.connect('acl', controller='getmachines')
        m.connect('acl/:machine', controller='getacl')
        m.connect('conf', controller='getconf')
        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 getroot(self, **kw):
        return ['acl', 'conf']
    
    def getacl(self, machine, **kw):
        """Build the ACL file for a machine
        """
        self.recache()
        machine = self.machines[machine]
        users = [acl.user for acl in machine.acl]
        return "\n".join(map(self.userToPrinc, users)
                 + ['include /etc/remctl/acl/web',
                    ''])
    
    def getconf(self, **kw):
        """Build the master conf file, with all machines
        """
        return '\n'.join("control %s /usr/sbin/invirt-remote-proxy-control"
                 " /etc/remctl/remconffs/acl/%s"
                 % (machine_name, machine_name)
                 for machine_name in self.getmachines())+'\n'
    
    def getmachines(self, **kw):
        """Get the list of VMs in the database, clearing the cache if it's 
        older than 15 seconds"""
        self.recache()
        return self.machines.keys()
    
    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(RemConfFS)
