#!/usr/bin/python

import routefs
from routes import Mapper

from syslog import *
from time import time
import sqlalchemy as sa

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.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 getroot(self, **kw):
        return ['acl', 'conf']
    
    def getacl(self, machine, **kw):
        """Build the ACL file for a machine
        """
        s = sa.sql.select([database.machine_access_table.c.user], # Field to select from
                          sa.sql.and_( # where clause
                database.machine_table.c.machine_id==database.machine_access_table.c.machine_id, # join field
                database.machine_table.c.name == machine), # filter field
                          from_obj=[database.machine_access_table, database.machine_table]) # from tables
        users = [self.userToPrinc(acl[0]) for acl in
                 database.session.execute(s)]
        return "\n".join(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. Does not cache to prevent race conditions."""
        return list(row[0] for row in database.session.execute(sa.sql.select([database.Machine.c.name])))
    
    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.kerberos.realm
        
        return princ.replace('.', '/') + '@' + realm

if __name__ == '__main__':
    database.connect()
    routefs.main(RemConfFS)
