Ignore:
Timestamp:
Oct 1, 2008, 12:20:21 PM (16 years ago)
Author:
broder
Message:

Update RemConfFS to use RouteFS

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/packages/sipb-xen-remote-server/files/usr/sbin/sipb-xen-remconffs

    r835 r982  
    11#!/usr/bin/python
    22
    3 import fuse
    4 from fuse import Fuse
    5 
    6 from time import time
    7 
    8 import stat     # for file properties
    9 import os         # for filesystem modes (O_RDONLY, etc)
    10 import errno   # for error number codes (ENOENT, etc)
    11                            # - note: these must be returned as negatives
     3import routefs
     4from routes import Mapper
    125
    136from syslog import *
     7from time import time
    148
    159from invirt import database
    1610from invirt.config import structs as config
    1711
    18 fuse.fuse_python_api = (0, 2)
    19 
    20 def getDepth(path):
    21         """
    22         Return the depth of a given path, zero-based from root ('/')
    23         """
    24         if path == '/':
    25                 return 0
    26         else:
    27                 return path.count('/')
    28 
    29 def getParts(path):
    30         """
    31         Return the slash-separated parts of a given path as a list
    32         """
    33         # [1:] to exclude leading empty element
    34         split = path.split('/')
    35         if split[-1]:
    36                 return split[1:]
    37         else:
    38                 return split[1:-1]
    39 
    40 def parse(path):
    41         parts = getParts(path)
    42         return parts, len(parts)
    43 
    44 class 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
    50                 self.st_uid = 0
    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 
    60 class RemConfFS(Fuse):
     12class RemConfFS(routefs.RouteFS):
    6113        """
    6214        RemConfFS creates a filesytem for configuring remctl, like this:
     
    6618        |   ...
    6719        |   `-- machinen
    68         `-- conf.d
    69             |-- machine1
    70             ...
    71             `-- machinen
    72 
     20        `-- conf
     21       
    7322        The machine list and the acls are drawn from a database.
    7423       
     
    8130                the user who mounts the filesystem (i.e. root)
    8231                """
    83                 Fuse.__init__(self, *args, **kw)
     32                super(RemConfFS, self).__init__(*args, **kw)
    8433                self.lasttime = time()
    85                 self.allow_other = 1
     34                self.fuse_args.add("allow_other", True)
    8635               
    8736                openlog('sipb-xen-remconffs ', LOG_PID, LOG_DAEMON)
    8837               
    8938                syslog(LOG_DEBUG, 'Init complete.')
    90 
     39       
     40        def make_map(self):
     41                m = Mapper()
     42                m.connect('', controller='getroot')
     43                m.connect('acl/:machine', controller='getacl')
     44                m.connect('conf', controller='getconf')
     45                return m
     46       
     47        def getroot(self, **kw):
     48                return ['acl', 'conf']
     49       
     50        def getacl(self, machine, **kw):
     51                """Build the ACL file for a machine
     52                """
     53                machine = database.Machine.get_by(name=machine)
     54                users = [acl.user for acl in machine.acl]
     55                return "\n".join(map(self.userToPrinc, users)
     56                                 + ['include /etc/remctl/acl/web',
     57                                    ''])
     58       
     59        def getconf(self, **kw):
     60                """Build the master conf file, with all machines
     61                """
     62                return '\n'.join("control %s /usr/sbin/sipb-xen-remote-proxy-control"
     63                                 " /etc/remctl/remconffs/acl/%s"
     64                                 % (machine_name, machine_name)
     65                                 for machine_name in self.getMachines())+'\n'
     66       
    9167        def getMachines(self):
    9268                """Get the list of VMs in the database, clearing the cache if it's
     
    9672                        database.clear_cache()
    9773                return [machine.name for machine in database.Machine.select()]
    98                
    99         def getacl(self, machine_name):
    100                 """Build the ACL file for a machine
    101                 """
    102                 machine = database.Machine.get_by(name=machine_name)
    103                 users = [acl.user for acl in machine.acl]
    104                 return "\n".join(map(self.userToPrinc, users)
    105                                  + ['include /etc/remctl/acl/web',
    106                                     ''])
    107                
    108         def getconf(self):
    109                 """Build the master conf file, with all machines
    110                 """
    111                 return '\n'.join("control %s /usr/sbin/sipb-xen-remote-proxy-control"
    112                                  " /etc/remctl/remconffs/acl/%s"
    113                                  % (machine_name, machine_name)
    114                                  for machine_name in self.getMachines())+'\n'
    115        
     74       
    11675        def userToPrinc(self, user):
    11776                """Convert Kerberos v4-style names to v5-style and append a default
     
    12584               
    12685                return princ.replace('.', '/') + '@' + realm
    127        
    128         def getattr(self, path):
    129                 """
    130                 - st_mode (protection bits)
    131                 - st_ino (inode number)
    132                 - st_dev (device)
    133                 - st_nlink (number of hard links)
    134                 - st_uid (user ID of owner)
    135                 - st_gid (group ID of owner)
    136                 - st_size (size of file, in bytes)
    137                 - st_atime (time of most recent access)
    138                 - st_mtime (time of most recent content modification)
    139                 - st_ctime (platform dependent; time of most recent metadata change on Unix,
    140                                         or the time of creation on Windows).
    141                 """
    142                
    143                 syslog(LOG_DEBUG, "*** getattr: " + path)
    144                
    145                 depth = getDepth(path)
    146                 parts = getParts(path)
    147                
    148                 st = MyStat()
    149                 if path == '/':
    150                         st.st_mode = stat.S_IFDIR | 0755
    151                         st.st_nlink = 2
    152                 elif depth == 1:
    153                         if parts[0] == 'acl':
    154                                 st.st_mode = stat.S_IFDIR | 0755
    155                                 st.st_nlink = 2
    156                         elif parts[0] == 'conf':
    157                                 st.st_mode = stat.S_IFREG | 0444
    158                                 st.st_nlink = 1
    159                                 st.st_size = len(self.getconf())
    160                         else:
    161                                 return -errno.ENOENT
    162                 elif depth == 2:
    163                         if parts[0] != 'acl':
    164                                 return -errno.ENOENT
    165                         if parts[1] not in self.getMachines():
    166                                 return -errno.ENOENT
    167                         st.st_mode = stat.S_IFREG | 0444
    168                         st.st_nlink = 1
    169                         st.st_size = len(self.getacl(parts[1]))
    170 
    171                 return st.toTuple()
    172        
    173         # This call isn't actually used in the version of Fuse on console, but we
    174         # wanted to leave it implemented to ease the transition in the future
    175         def readdir(self, path, offset):
    176                 """Return a generator with the listing for a directory
    177                 """
    178                 syslog(LOG_DEBUG, '*** readdir %s %s' % (path, offset))
    179                 for (value, zero) in self.getdir(path):
    180                         yield fuse.Direntry(value)
    181        
    182         def getdir(self, path):
    183                 """Return a list of tuples of the form (item, 0) with the contents of
    184                 the directory path
    185                
    186                 Fuse doesn't add '.' or '..' on its own, so we have to
    187                 """
    188                 syslog(LOG_DEBUG, '*** getdir %s' % path)
    189                
    190                 parts, depth = parse(path)
    191 
    192                 if depth == 0:
    193                         contents = ('acl', 'conf')
    194                 elif depth == 1:
    195                         if parts[0] == 'acl':
    196                                 contents = self.getMachines()
    197                         else:
    198                                 return -errno.ENOENT
    199                 else:
    200                         return -errno.ENOTDIR
    201 
    202                 # Format the list the way that Fuse wants it - and don't forget to add
    203                 # '.' and '..'
    204                 return [(i, 0) for i in (list(contents) + ['.', '..'])]
    205 
    206         def read(self, path, length, offset):
    207                 """Read length bytes starting at offset of path. In most cases, this
    208                 just gets passed on to the OS
    209                 """
    210                 syslog(LOG_DEBUG, '*** read %s %s %s' % (path, length, offset))
    211                
    212                 parts, depth = parse(path)
    213                
    214                 if depth == 0:
    215                         return -errno.EISDIR
    216                 elif parts[0] == 'conf':
    217                         return self.getconf()[offset:offset+length]
    218                 elif parts[0] == 'acl':
    219                         if depth == 1:
    220                                 return -errno.EISDIR
    221                         if parts[1] in self.getMachines():
    222                                 return self.getacl(parts[1])[offset:offset+length]
    223                 return -errno.ENOENT
    224        
    225         def readlink(self, path):
    226                 syslog(LOG_DEBUG, '*** readlink %s' % path)
    227                 return -errno.ENOENT
    228 
    22986
    23087if __name__ == '__main__':
    23188        database.connect()
    232         usage="""
    233 $0 [mount_path]
    234 """
    235         server = RemConfFS()
    236         server.flags = 0
    237         server.main()
     89        routefs.main(RemConfFS)
Note: See TracChangeset for help on using the changeset viewer.