| 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 = 0 | 
|---|
| 30 |         self.machines = [] | 
|---|
| 31 |         self.fuse_args.add("allow_other", True) | 
|---|
| 32 |          | 
|---|
| 33 |         openlog('invirt-consolefs ', LOG_PID, LOG_DAEMON) | 
|---|
| 34 |          | 
|---|
| 35 |         syslog(LOG_DEBUG, 'Init complete.') | 
|---|
| 36 |      | 
|---|
| 37 |     def make_map(self): | 
|---|
| 38 |         m = Mapper() | 
|---|
| 39 |         m.connect('', controller='getMachines') | 
|---|
| 40 |         m.connect(':machine', controller='getMirror') | 
|---|
| 41 |         m.connect(':machine/.k5login', controller='getK5login') | 
|---|
| 42 |         m.connect(':machine/*(path)', controller='getMirror') | 
|---|
| 43 |         return m | 
|---|
| 44 |      | 
|---|
| 45 |     def recache(self): | 
|---|
| 46 |         if time() - self.lasttime > 5: | 
|---|
| 47 |             self.lasttime = time() | 
|---|
| 48 |             database.clear_cache() | 
|---|
| 49 |             self.machines = dict((machine.name, machine) for machine in database.session.query(database.Machine).all()) | 
|---|
| 50 |  | 
|---|
| 51 |     def getMachines(self, **kw): | 
|---|
| 52 |         self.recache() | 
|---|
| 53 |         return self.machines.keys() | 
|---|
| 54 |      | 
|---|
| 55 |     def getMirror(self, machine, path='', **kw): | 
|---|
| 56 |         """Translate the path into its realpath equivalent, and return that | 
|---|
| 57 |         """ | 
|---|
| 58 |         real = realpath + path | 
|---|
| 59 |         if os.path.isdir(real): | 
|---|
| 60 |             # The list is converted to a set so that we can handle the case  | 
|---|
| 61 |             # where there is already a .k5login in the realpath gracefully     | 
|---|
| 62 |             return routefs.Directory(set(os.listdir(real) + ['.k5login'])) | 
|---|
| 63 |         elif os.path.islink(real): | 
|---|
| 64 |             return routefs.Symlink(os.readlink(real)) | 
|---|
| 65 |         elif os.path.isfile(real): | 
|---|
| 66 |             return open(real).read() | 
|---|
| 67 |         else: | 
|---|
| 68 |             return -errno.EINVAL | 
|---|
| 69 |      | 
|---|
| 70 |     def getK5login(self, machine, **kw): | 
|---|
| 71 |         self.recache() | 
|---|
| 72 |         machine = self.machines[machine] | 
|---|
| 73 |         users = [acl.user for acl in machine.acl] | 
|---|
| 74 |         return "\n".join(map(self.userToPrinc, users) + ['']) | 
|---|
| 75 |      | 
|---|
| 76 |     def mirrorPath(self, path): | 
|---|
| 77 |         """Translate a virtual path to its real path counterpart""" | 
|---|
| 78 |         return realpath + "/".join(getParts(path)[1:]) | 
|---|
| 79 |      | 
|---|
| 80 |     def userToPrinc(self, user): | 
|---|
| 81 |         """Convert Kerberos v4-style names to v5-style and append a default | 
|---|
| 82 |         realm if none is specified | 
|---|
| 83 |         """ | 
|---|
| 84 |         if '@' in user: | 
|---|
| 85 |             (princ, realm) = user.split('@') | 
|---|
| 86 |         else: | 
|---|
| 87 |             princ = user | 
|---|
| 88 |             realm = config.authn[0].realm | 
|---|
| 89 |          | 
|---|
| 90 |         return princ.replace('.', '/') + '@' + realm | 
|---|
| 91 |  | 
|---|
| 92 | if __name__ == '__main__': | 
|---|
| 93 |     database.connect() | 
|---|
| 94 |     routefs.main(ConsoleFS) | 
|---|