fix single key files and cache vsys call for efficiency
[playground.git] / omf_keys / key_fs.py
1 #!/usr/bin/python
2
3 # A FUSE filesystem implementation to provide a file interface for
4 # vsys_publickeys VSYS script. To be used by OMF Resource Controller.
5
6 # Usage: ./keys_fs.py /keys
7 #        ls /keys
8 #        cat /keys/all
9
10 # NOTE:
11 # Sliver has to have following ccapabilities set.
12 # SECURE_MOUNT
13 # BINARY_MOUNT
14 #
15 # we also depend on fuse and python-fuse packages.
16 #
17
18
19 import os
20 import sys
21 import stat
22 import errno
23 import fuse
24 import fcntl
25 import select
26 from fuse import Fuse
27
28 fuse.fuse_python_api = (0, 2)
29
30 keys_dir = "/keys"
31 all_ssh_keys = None
32 all_ssh_keys_dict = None
33
34 def read_keys():
35     global all_ssh_keys
36     if all_ssh_keys:
37         return all_ssh_keys
38         
39     fin = os.open("/vsys/publickeys.in", os.O_NONBLOCK | os.O_WRONLY)
40     fout = os.open("/vsys/publickeys.out", os.O_NONBLOCK | os.O_RDONLY)
41     
42     in_flags = fcntl.fcntl(fin, fcntl.F_GETFL)
43     out_flags = fcntl.fcntl(fin, fcntl.F_GETFL)
44     
45     res = select.select([fout], [], [])
46     
47     fcntl.fcntl(fin, fcntl.F_SETFL, in_flags & ~os.O_NONBLOCK)
48     fcntl.fcntl(fout, fcntl.F_SETFL, out_flags & ~os.O_NONBLOCK)
49     
50     f = os.fdopen(fout, "r")
51     all_ssh_keys = f.read()
52     return all_ssh_keys
53
54
55 def all_keys():
56     global all_ssh_keys_dict
57     if all_ssh_keys_dict:
58         return all_ssh_keys_dict
59
60     keys = read_keys()
61     files = {}
62     num = 0
63     for line in keys.split('\n'):
64         line = line.strip()
65         if not line: continue
66
67         filename = ""
68         in_key = False
69         in_name = False
70         fields = line.split()
71         for f in fields:
72             f = f.strip()
73             if f.startswith("ssh-"):
74                 in_key = True
75                 continue
76             elif in_key:
77                 in_name = True
78                 in_key = False
79                 continue
80             elif in_name:
81                 if filename:
82                     filename = "%s_%s" % (filename, f)
83                 else:
84                     filename = f
85
86         if not filename:
87             num += 1
88             files["unnamed_key%d" % num] = line
89         else:
90             files[filename] = "%s\n" % line
91
92     return files
93
94 class MyStat(fuse.Stat):
95     def __init__(self):
96         self.st_mode = 0
97         self.st_ino = 0
98         self.st_dev = 0
99         self.st_nlink = 0
100         self.st_uid = 0
101         self.st_gid = 0
102         self.st_size = 0
103         self.st_atime = 0
104         self.st_mtime = 0
105         self.st_ctime = 0
106
107 class KeyFS(Fuse):
108
109     def __init__(self, *args, **kw):
110         Fuse.__init__(self, *args, **kw)
111
112     def getattr(self, path):
113         st = MyStat()
114         if path == '/':
115             st.st_mode = stat.S_IFDIR | 0755
116             st.st_nlink = 2
117         elif os.path.basename(path) == "all":
118             st.st_mode = stat.S_IFREG | 0444
119             st.st_nlink = 1
120             st.st_size = len(read_keys())
121         else:
122             filename = os.path.basename(path)
123             keys = all_keys()
124             st.st_mode = stat.S_IFREG | 0444
125             st.st_nlink = 1
126             try:
127                 st.st_size = len(keys[filename])
128             except:
129                 st.st_size = 0
130         return st
131
132     def readdir(self, path, offset):
133         files = ['.', '..', "all"]
134         keys = all_keys()
135         files.extend(keys.keys())
136         for r in files:
137             yield fuse.Direntry(r)
138
139     def open(self, path, flags):
140         accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR
141         if (flags & accmode) != os.O_RDONLY:
142             return -errno.EACCES
143
144     def read (self, path, size, offset):
145         if os.path.basename(path) == "all":
146             content = read_keys()
147         else:
148             filename = os.path.basename(path)
149             keys = all_keys()
150             content = keys[filename]
151
152         slen = len(content)
153
154         if offset < slen:
155             if offset + size > slen:
156                 size = slen - offset
157             buf = content[offset:offset+size]
158         else:
159             buf = ''
160         return buf
161
162
163
164 if __name__ == '__main__':
165     fs = KeyFS()
166     fs.multithreaded = 0
167     fs.parse(values=fs, errex=1)
168     try:
169         if fs.fuse_args.mount_expected():
170             os.chdir("/")
171     except OSError:
172         sys.stderr.write("can't enter root of underlying filesystem\n")
173         sys.exit(1)
174
175     fs.main()