source: trunk/packages/sipb-xen-console/files/usr/bin/sipb-xen-consolefs @ 347

Last change on this file since 347 was 344, checked in by broder, 17 years ago

New sipb-xen-console. Now with more magic - and more working

This package installed onto a clean Debian system should do all of the setup
for a console server except for copying the ssh private keys, granting access
to the Postgres database, and Kerberos keytabs

  • Property svn:executable set to *
File size: 4.5 KB
RevLine 
[335]1#!/usr/bin/python
2
3import fuse
4from fuse import Fuse
5
6from time import time
7
8import stat     # for file properties
9import os         # for filesystem modes (O_RDONLY, etc)
10import errno   # for error number codes (ENOENT, etc)
11                           # - note: these must be returned as negatives
12
[344]13import sipb_xen_database
14
[335]15fuse.fuse_python_api = (0, 2)
16
17realpath = "/home/machines/"
18
19def dirFromList(list):
20        """
21        Return a properly formatted list of items suitable to a directory listing.
22        ['a', 'b', 'c'] => [('a', 0), ('b', 0), ('c', 0)]
23        """
24        return [(x, 0) for x in list]
25
26def getDepth(path):
27        """
28        Return the depth of a given path, zero-based from root ('/')
29        """
30        if path == '/':
31                return 0
32        else:
33                return path.count('/')
34
35def getParts(path):
36        """
37        Return the slash-separated parts of a given path as a list
38        """
39        if path == '/':
40                return ['/']
41        else:
42                return path[1:].split('/')
43
44class MyStat:
45        def __init__(self):
46                self.st_mode = 0
47                self.st_ino = 0
48                self.st_dev = 0
49                self.st_nlink = 0
[344]50                self.st_uid = 0
[335]51                self.st_gid = 0
52                self.st_size = 0
53                self.st_atime = 0
54                self.st_mtime = 0
55                self.st_ctime = 0
56       
57        def toTuple(self):
58                return (self.st_mode, self.st_ino, self.st_dev, self.st_nlink, self.st_uid, self.st_gid, self.st_size, self.st_atime, self.st_mtime, self.st_ctime)
59
60class ConsoleFS(Fuse):
61        """
62        """
63       
64        def __init__(self, *args, **kw):
65                Fuse.__init__(self, *args, **kw)
[344]66                self.lasttime = time()
67                self.allow_other = 1
[335]68                print 'Init complete.'
69       
70        def mirrorPath(self, path):
71                return realpath + "/".join(getParts(path)[1:])
72       
[344]73        def getMachines(self):
74                if time() - self.lasttime > 15:
75                        self.lasttime = time()
76                        sipb_xen_database.clear_cache()
77                return [machine.name for machine in sipb_xen_database.Machine.select()]
78       
79        def getUid(self, machine_name):
80                return sipb_xen_database.Machine.get_by(name=machine_name).machine_id + 1000
81       
82        def getK5login(self, machine_name):
83                machine = sipb_xen_database.Machine.get_by(name=machine_name)
84                users = [acl.user for acl in machine.acl]
85                return "\n".join(map(self.userToPrinc, users) + [''])
86       
87        def userToPrinc(self, user):
88                if '@' in user:
89                        (princ, realm) = user.split('@')
90                else:
91                        princ = user
92                        realm = "ATHENA.MIT.EDU"
93               
94                return princ.replace('.', '/') + realm
95       
[335]96        def getattr(self, path):
97                """
98                - st_mode (protection bits)
99                - st_ino (inode number)
100                - st_dev (device)
101                - st_nlink (number of hard links)
102                - st_uid (user ID of owner)
103                - st_gid (group ID of owner)
104                - st_size (size of file, in bytes)
105                - st_atime (time of most recent access)
106                - st_mtime (time of most recent content modification)
107                - st_ctime (platform dependent; time of most recent metadata change on Unix,
108                                        or the time of creation on Windows).
109                """
110               
111                print "*** getattr: " + path
112               
113                depth = getDepth(path)
114                parts = getParts(path)
115               
116                st = MyStat()
117                if path == '/':
118                        st.st_mode = stat.S_IFDIR | 0755
119                        st.st_nlink = 2
120                elif depth == 1:
[344]121                        if parts[-1] in self.getMachines():
[335]122                                st.st_mode = stat.S_IFDIR | 0755
123                                st.st_nlink = 2
[344]124                                st.st_uid = st.st_gid = self.getUid(parts[0])
[335]125                        else:
126                                return -errno.ENOENT
127                elif depth == 2 and parts[-1] == '.k5login':
128                        st.st_mode = stat.S_IFREG | 0444
129                        st.st_nlink = 1
[344]130                        st.st_size = len(self.getK5login(parts[0]))
131                        st.st_uid = st.st_gid = self.getUid(parts[0])
[335]132                else:
[344]133                        stats = list(os.lstat(self.mirrorPath(path)))
134                        stats[4:6] = [self.getUid(parts[0])] * 2
135                        return tuple(stats)
[335]136                return st.toTuple()
137       
138        def readdir(self, path, offset):
139                print '*** readdir', path, offset
[344]140                for (value, zero) in self.getdir(path):
141                        yield fuse.Direntry(value)
142       
143        def getdir(self, path):
144                print '*** getdir', path
[335]145                if path == '/':
[344]146                        contents = ['.', '..']+self.getMachines()
[335]147                elif getDepth(path) == 1:
[344]148                        contents = set(os.listdir(self.mirrorPath(path)) + ['.k5login', '.', '..'])
[335]149                else:
[344]150                        contents = os.listdir(self.mirrorPath(path)) + ['.', '..']
151                return [(i, 0) for i in contents]
[335]152       
153        def read ( self, path, length, offset ):
154                print '*** read', path, length, offset
155               
[344]156                parts = getParts(path)
157               
[335]158                if getDepth(path) < 2:
159                        return -errno.ENOENT
[344]160                elif parts[1:] == ['.k5login']:
161                        if parts[0] not in self.getMachines():
162                                return -errno.ENOENT
163                        else:
164                                return self.getK5login(parts[0])[offset:length + offset]
[335]165                else:
166                        fname = self.mirrorPath(path)
167                        if not os.path.isfile(fname):
168                                return -errno.ENOENT
169                        else:
170                                f = open(fname)
171                                f.seek(offset)
172                                return f.read(length)
173
174if __name__ == '__main__':
[344]175        sipb_xen_database.connect('postgres://sipb-xen@sipb-xen-dev.mit.edu/sipb_xen')
[335]176        usage="""
177ConsoleFS [mount_path]
178"""
179        server = ConsoleFS()
180        server.flags = 0
181        server.main()
Note: See TracBrowser for help on using the repository browser.