New sipb-xen-console. Now with more magic - and more working
[invirt/packages/invirt-console.git] / files / usr / bin / sipb-xen-consolefs
index 7cd3766..380c94b 100755 (executable)
@@ -10,11 +10,11 @@ import os     # for filesystem modes (O_RDONLY, etc)
 import errno   # for error number codes (ENOENT, etc)
                           # - note: these must be returned as negatives
 
+import sipb_xen_database
+
 fuse.fuse_python_api = (0, 2)
 
-machines = ['moo17', 'remus']
 realpath = "/home/machines/"
-uid = 1000
 
 def dirFromList(list):
        """
@@ -47,7 +47,7 @@ class MyStat:
                self.st_ino = 0
                self.st_dev = 0
                self.st_nlink = 0
-               self.st_uid = uid
+               self.st_uid = 0
                self.st_gid = 0
                self.st_size = 0
                self.st_atime = 0
@@ -63,11 +63,36 @@ class ConsoleFS(Fuse):
        
        def __init__(self, *args, **kw):
                Fuse.__init__(self, *args, **kw)
+               self.lasttime = time()
+               self.allow_other = 1
                print 'Init complete.'
        
        def mirrorPath(self, path):
                return realpath + "/".join(getParts(path)[1:])
        
+       def getMachines(self):
+               if time() - self.lasttime > 15:
+                       self.lasttime = time()
+                       sipb_xen_database.clear_cache()
+               return [machine.name for machine in sipb_xen_database.Machine.select()]
+       
+       def getUid(self, machine_name):
+               return sipb_xen_database.Machine.get_by(name=machine_name).machine_id + 1000
+       
+       def getK5login(self, machine_name):
+               machine = sipb_xen_database.Machine.get_by(name=machine_name)
+               users = [acl.user for acl in machine.acl]
+               return "\n".join(map(self.userToPrinc, users) + [''])
+       
+       def userToPrinc(self, user):
+               if '@' in user:
+                       (princ, realm) = user.split('@')
+               else:
+                       princ = user
+                       realm = "ATHENA.MIT.EDU"
+               
+               return princ.replace('.', '/') + realm
+       
        def getattr(self, path):
                """
                - st_mode (protection bits)
@@ -93,38 +118,50 @@ class ConsoleFS(Fuse):
                        st.st_mode = stat.S_IFDIR | 0755
                        st.st_nlink = 2
                elif depth == 1:
-                       if parts[-1] in machines:
+                       if parts[-1] in self.getMachines():
                                st.st_mode = stat.S_IFDIR | 0755
                                st.st_nlink = 2
+                               st.st_uid = st.st_gid = self.getUid(parts[0])
                        else:
                                return -errno.ENOENT
                elif depth == 2 and parts[-1] == '.k5login':
                        st.st_mode = stat.S_IFREG | 0444
                        st.st_nlink = 1
-                       st.st_size = 17
+                       st.st_size = len(self.getK5login(parts[0]))
+                       st.st_uid = st.st_gid = self.getUid(parts[0])
                else:
-                       st = os.lstat(self.mirrorPath(path))
+                       stats = list(os.lstat(self.mirrorPath(path)))
+                       stats[4:6] = [self.getUid(parts[0])] * 2
+                       return tuple(stats)
                return st.toTuple()
        
        def readdir(self, path, offset):
                print '*** readdir', path, offset
+               for (value, zero) in self.getdir(path):
+                       yield fuse.Direntry(value)
+       
+       def getdir(self, path):
+               print '*** getdir', path
                if path == '/':
-                       for r in  ['.', '..']+machines:
-                               yield fuse.Direntry(r)
+                       contents = ['.', '..']+self.getMachines()
                elif getDepth(path) == 1:
-                       for r in set(os.listdir(self.mirrorPath(path)) + ['.k5login']):
-                               yield fuse.Direntry(r)
+                       contents = set(os.listdir(self.mirrorPath(path)) + ['.k5login', '.', '..'])
                else:
-                       for r in os.listdir(self.mirrorPath(path)):
-                               yield fuse.Direntry(r)
+                       contents = os.listdir(self.mirrorPath(path)) + ['.', '..']
+               return [(i, 0) for i in contents]
        
        def read ( self, path, length, offset ):
                print '*** read', path, length, offset
                
+               parts = getParts(path)
+               
                if getDepth(path) < 2:
                        return -errno.ENOENT
-               elif getParts(path)[1:] == ['.k5login']:
-                       pass
+               elif parts[1:] == ['.k5login']:
+                       if parts[0] not in self.getMachines():
+                               return -errno.ENOENT
+                       else:
+                               return self.getK5login(parts[0])[offset:length + offset]
                else:
                        fname = self.mirrorPath(path)
                        if not os.path.isfile(fname):
@@ -135,6 +172,7 @@ class ConsoleFS(Fuse):
                                return f.read(length)
 
 if __name__ == '__main__':
+       sipb_xen_database.connect('postgres://sipb-xen@sipb-xen-dev.mit.edu/sipb_xen')
        usage="""
 ConsoleFS [mount_path]
 """