Add a dummy console for the console server's conserver in case no VMs
[invirt/packages/invirt-console.git] / files / usr / bin / sipb-xen-consolefs
1 #!/usr/bin/python
2
3 import routefs
4 from routes import Mapper
5
6 from syslog import *
7 from time import time
8
9 import os
10 import errno
11
12 from invirt.config import structs as config
13 from invirt import database
14
15 realpath = "/home/machines/"
16
17 class ConsoleFS(routefs.RouteFS):
18         """
19         ConsoleFS creates a series of subdirectories each mirroring the same real
20         directory, except for a single file - the .k5login - which is dynamically
21         generated for each subdirectory
22         """
23         
24         def __init__(self, *args, **kw):
25                 """Initialize the filesystem and set it to allow_other access besides
26                 the user who mounts the filesystem (i.e. root)
27                 """
28                 super(ConsoleFS, self).__init__(*args, **kw)
29                 self.lasttime = time()
30                 self.fuse_args.add("allow_other", True)
31                 
32                 openlog('sipb-xen-consolefs ', LOG_PID, LOG_DAEMON)
33                 
34                 syslog(LOG_DEBUG, 'Init complete.')
35
36         def make_map(self):
37                 m = Mapper()
38                 m.connect('', controller='getMachines')
39                 m.connect(':machine', controller='getMirror')
40                 m.connect(':machine/.k5login', controller='getK5login')
41                 m.connect(':machine/*(path)', controller='getMirror')
42                 return m
43         
44         def getMachines(self, **kw):
45                 """Get the list of VMs in the database, clearing the cache if it's 
46                 older than 15 seconds"""
47                 if time() - self.lasttime > 15:
48                         self.lasttime = time()
49                         database.clear_cache()
50                 return [machine.name for machine in database.Machine.query()]
51         
52         def getMirror(self, machine, path='', **kw):
53                 """Translate the path into its realpath equivalent, and return that
54                 """
55                 real = realpath + path
56                 if os.path.isdir(real):
57                         # The list is converted to a set so that we can handle the case 
58                         # where there is already a .k5login in the realpath gracefully    
59                         return routefs.Directory(set(os.listdir(real) + ['.k5login']))
60                 elif os.path.islink(real):
61                         return routefs.Symlink(os.readlink(real))
62                 elif os.path.isfile(real):
63                         return open(real).read()
64                 else:
65                         return -errno.EINVAL
66         
67         def getK5login(self, machine, **kw):
68                 """Build the ACL for a machine and turn it into a .k5login file
69                 """
70                 machine = database.Machine.query().filter_by(name=machine).one()
71                 users = [acl.user for acl in machine.acl]
72                 return "\n".join(map(self.userToPrinc, users) + [''])
73         
74         def mirrorPath(self, path):
75                 """Translate a virtual path to its real path counterpart"""
76                 return realpath + "/".join(getParts(path)[1:])
77         
78         def userToPrinc(self, user):
79                 """Convert Kerberos v4-style names to v5-style and append a default
80                 realm if none is specified
81                 """
82                 if '@' in user:
83                         (princ, realm) = user.split('@')
84                 else:
85                         princ = user
86                         realm = config.authn[0].realm
87                 
88                 return princ.replace('.', '/') + '@' + realm
89
90 if __name__ == '__main__':
91         database.connect()
92         routefs.main(ConsoleFS)