1164.2.33
by David Coles
Developer Specific system architecture documentation. |
1 |
.. IVLE - Informatics Virtual Learning Environment
|
2 |
Copyright (C) 2007-2009 The University of Melbourne
|
|
3 |
||
4 |
.. This program is free software; you can redistribute it and/or modify
|
|
5 |
it under the terms of the GNU General Public License as published by
|
|
6 |
the Free Software Foundation; either version 2 of the License, or
|
|
7 |
(at your option) any later version.
|
|
8 |
||
9 |
.. This program is distributed in the hope that it will be useful,
|
|
10 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12 |
GNU General Public License for more details.
|
|
13 |
||
14 |
.. You should have received a copy of the GNU General Public License
|
|
15 |
along with this program; if not, write to the Free Software
|
|
16 |
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
17 |
||
18 |
*******************
|
|
19 |
System Architecture
|
|
20 |
*******************
|
|
21 |
||
22 |
IVLE is a complex piece of software that integrates closely with the |
|
23 |
underlying system. It can be considered part web service and part local system |
|
24 |
daemon. Due to the implementation of these parts it is tied to Apache Web |
|
1164.2.39
by David Coles
Dispatch developer documentation. |
25 |
Server (mainly due to the use of mod_python) and Linux. |
26 |
||
27 |
||
28 |
Dispatch
|
|
29 |
========
|
|
30 |
||
31 |
IVLE uses mod_python_ to allow Python scripts to be called from Apache. We |
|
32 |
register the :mod:`ivle.dispatch` module as the ``PythonHandler`` in the |
|
33 |
associated VirtualHost, allowing us to intercept all HTTP requests to the web |
|
34 |
server. |
|
35 |
||
36 |
The :mod:`ivle.dispatch` module is responsible for mapping requests from the |
|
37 |
client to the correct application plugin. Plugins can be specified by placing |
|
38 |
a :file:`*.conf` file into the :file:`/etc/ivle/plugins.d/` directory |
|
39 |
containing lines of the form :samp:`[{plugin_module}#{classname}]`. |
|
40 |
||
41 |
.. TODO: Document Plugin Format and Routing Strings
|
|
42 |
||
43 |
In future, this may be ported to a WSGI (:pep:`333`) based dispatch to allow |
|
44 |
IVLE to be run on web servers other than Apache. |
|
45 |
||
46 |
.. _mod_python: http://www.modpython.org/ |
|
47 |
||
48 |
||
49 |
Templating
|
|
50 |
----------
|
|
1164.2.43
by Matt Giuca
doc/dev/architecture: Genshi is now the standard. Added note about the raw stream for old-school apps. |
51 |
IVLE uses the Genshi_ XHTML template system to generate all HTML pages. We |
52 |
have an inheritance-based "views" system. :class:`BaseView` is a class from |
|
53 |
which all views derive. |
|
1164.2.39
by David Coles
Dispatch developer documentation. |
54 |
|
55 |
There are 3 sub-types of :class:`BaseView` (more can be implemented if |
|
56 |
necessary): |
|
57 |
||
58 |
* XHTML-Templated
|
|
59 |
* browser, console, debuginfo, diff, forum, groups, help, home, logout,
|
|
60 |
settings, subjects, svnlog, tos, tutorial |
|
61 |
* Raw byte streaming
|
|
62 |
* download, server
|
|
63 |
* JSON service
|
|
64 |
* consoleservice, fileservice, tutorialservice, userservice
|
|
65 |
||
66 |
The apps each derive from one of the above. |
|
67 |
||
1164.2.43
by Matt Giuca
doc/dev/architecture: Genshi is now the standard. Added note about the raw stream for old-school apps. |
68 |
.. note:: |
69 |
IVLE used to write its HTML output as a raw stream to an output file, until |
|
70 |
it was refactored to use Genshi. All apps which haven't yet been refactored |
|
71 |
properly were ported to use the "raw byte streaming" view. |
|
1164.2.39
by David Coles
Dispatch developer documentation. |
72 |
|
73 |
.. _Genshi: http://genshi.edgewall.org/ |
|
1164.2.33
by David Coles
Developer Specific system architecture documentation. |
74 |
|
75 |
Jail System
|
|
76 |
===========
|
|
77 |
||
78 |
One of the main features of IVLE is it's ability to execute user's code in a |
|
79 |
customised environment that prevents access to other users files or underlying |
|
80 |
file system as well as placing basic resource limits to prevent users from |
|
81 |
accidentally exhausting shared resources such as CPU time and memory. |
|
82 |
||
1164.2.35
by David Coles
More clarification of the jail system |
83 |
|
84 |
Trampoline
|
|
85 |
----------
|
|
86 |
||
1164.2.33
by David Coles
Developer Specific system architecture documentation. |
87 |
To each user, it appears that they have their own private Unix filesystem |
88 |
containing software, libraries and a home directory to do with what they |
|
89 |
please. This is mainly done by the setuid root program ``trampoline`` (See
|
|
90 |
:file:`bin/trampoline/trampoline.c`) which mounts the users home directory, |
|
91 |
sets up the users environment, jumps into the user's jail using the |
|
92 |
:manpage:`chroot(2)` system call and finally drops privileges to the desired |
|
93 |
user and group. |
|
94 |
||
95 |
To prevent abuse, ``trampoline`` can only be used by root or one of the uids
|
|
1164.2.35
by David Coles
More clarification of the jail system |
96 |
specified when trampoline is built by ``setup.py build`` (defaults to UID 33,
|
97 |
www-data on Debian systems). Since it's one of two C programs involved in IVLE |
|
98 |
and runs setuid root it is rather secuity sensative. |
|
1164.2.33
by David Coles
Developer Specific system architecture documentation. |
99 |
|
1164.2.35
by David Coles
More clarification of the jail system |
100 |
Base Image Generation
|
101 |
---------------------
|
|
1164.2.33
by David Coles
Developer Specific system architecture documentation. |
102 |
|
103 |
All user jails share a common base image that contains the files required for |
|
104 |
both IVLE's operation and for executing user code. This base image is |
|
105 |
generated automatically by the ``ivle-buildjail`` script. This then calls the
|
|
106 |
distribution dependant details in :mod:`ivle.jailbuilder` module. At present |
|
107 |
we only support building jails for Debian derived systems using |
|
108 |
:program:`debootstrap`. |
|
109 |
||
110 |
The contents of the base image contains a few core packages required for the |
|
111 |
operation of IVLE - Python and the Python CJSON and SVN libraries. Other |
|
112 |
options that can be configured in :file:`/etc/ivle/ivle.conf` are the file |
|
113 |
mirror that debootstrap should use, the suite to build (such as hardy or |
|
114 |
jaunty), extra apt-sources, extra apt keys and any additional packages to |
|
115 |
install. |
|
116 |
||
117 |
To prevent users from altering files in the base image we change the |
|
118 |
permissions of :file:`/tmp`, :file:`/var/tmp` and :file:`/var/lock` to not be |
|
119 |
world writeable and check that no other files are world writeable. |
|
120 |
||
121 |
Finally we make the user dependent :file:`/etc/passwd` and |
|
122 |
:file:`/etc/ivle/ivle.conf` symlinks to files in the :file:`/home` directory |
|
123 |
so that they will be used when we mount a user's home directory. |
|
124 |
||
125 |
Mounting Home Directories
|
|
126 |
-------------------------
|
|
127 |
||
128 |
To give the appearance of a private file system we need to merge together a |
|
129 |
user's local home directory with the base image. In the first release of IVLE |
|
130 |
this was done off-line by hardlinking all the files into the target directory, |
|
131 |
but for more than a handful of users this process could take several hours and |
|
132 |
also ran the risk of exhausting inodes on the underlying file system. |
|
133 |
||
134 |
The first solution was to use `AUFS <http://aufs.sourceforge.net/>`_ to mount |
|
135 |
the user's home directory over a read-only version of the base on demand. This |
|
136 |
was implemented as part of ``trampoline`` and used a secondary program
|
|
137 |
``timount`` (see :file:`bin/timount/timount.c`) run at regular intervals to |
|
1164.2.35
by David Coles
More clarification of the jail system |
138 |
unmount unused jails. This uses the :const:`MNT_EXPIRE` flag for |
139 |
:manpage:`umount(2)` (available since Linux 2.6.8) that only unmounts a |
|
140 |
directory if it hasn't been accessed since the previous call with |
|
141 |
:const:`MNT_EXPIRE`. |
|
1164.2.33
by David Coles
Developer Specific system architecture documentation. |
142 |
|
143 |
While quite effective, AUFS appears to cause NFS caching issues when IVLE is |
|
1164.2.35
by David Coles
More clarification of the jail system |
144 |
run as a cluster as well as questionable inclusion status in newer |
145 |
distributions. The current system used in IVLE the much older *bind mount*
|
|
146 |
feature which allows directories to be accessible from another location in the |
|
147 |
file system. By carefully read-only bind mounting the jail image and then bind |
|
1164.2.33
by David Coles
Developer Specific system architecture documentation. |
148 |
mounting the user's :file:`/home` and :file:`/tmp` directory data over the top |
149 |
we can create a jail with only three bind mounts and at virtually no |
|
150 |
filesystem overhead. |
|
151 |
||
152 |
Entering the Jail
|
|
153 |
-----------------
|
|
154 |
||
155 |
Before running the specified program in the users jail we need to |
|
156 |
:manpage:`chroot(2)` into the users jail and update the processes environment |
|
157 |
so that we have the correct environment variables and user/group ids. |
|
158 |
||
159 |
At this stage we also may apply a number of resource limits (see |
|
160 |
:manpage:`setrlimit`) to prevent run away processes (such as those containing |
|
161 |
infinite loops or "fork bombs") from exhausting all system resources. The |
|
162 |
default limits are on maximum address space (:const:`RLIMIT_AS`), process data |
|
163 |
space (:const:`RLIMIT_DATA`), core dump size (:const:`RLIMIT_CORE`), CPU time |
|
164 |
(:const:`RLIMIT_CPU`), file size (:const:`RLIMIT_FSIZE`) and number of |
|
165 |
processes that may be spawned (:const:`RLIMIT_NPROC`). |
|
166 |
||
167 |
Unfortunately due to glibc's :manpage:`malloc(2)` implementation being able to |
|
168 |
allocate memory using :manpage:`mmap(2)`, :const:`RLIMIT_DATA` does not |
|
169 |
provide an effective limit on the amount of memory that a process can allocate |
|
170 |
(short of applying a kernel patch). Thus the only way to limit memory |
|
171 |
allocations is by placing limits on the address space, but this can cause |
|
172 |
problems with certain applications that allocate far larger address spaces |
|
173 |
than the real memory used. For this reason :const:`RLIMIT_AS` is currently set |
|
174 |
very large. |
|
175 |
||
1164.2.37
by David Coles
Chat protocol documentation and some stuff on Console. |
176 |
Python Console
|
177 |
==============
|
|
178 |
||
179 |
IVLE provides a web based programming console, exposing similar features to |
|
180 |
Python's command line console. It is built around python script |
|
181 |
:file:`services/python-console` which opens up a socket to which `JSON`_ |
|
182 |
encoded chat requests can be made. A new console is typically from launched on |
|
183 |
demand by the web client to the HTTP API, which in turn calls the wrapper |
|
184 |
class :class:`ivle.console.Console` to start a new console in the user's jail. |
|
185 |
||
186 |
.. _JSON: http://json.org |
|
187 |
||
188 |
User Management Server
|
|
189 |
======================
|
|
190 |
||
1164.2.38
by David Coles
User Management Server Development Documentation |
191 |
The **User Management Server** is a daemon responsible for handling privileged
|
192 |
actions on IVLE and should be launched along with IVLE. It is primarily |
|
193 |
responsible for: |
|
194 |
||
195 |
* Creating user jails, Subversion repositories, and Subversion authentication
|
|
196 |
credentials. |
|
197 |
* Creating group Subversion repositories.
|
|
198 |
* Rebuilding Subversion authorization files.
|
|
199 |
||
200 |
Communication with the Server is done using the `Chat Protocol`_. To prevent
|
|
201 |
unauthorized use, communication with the User Management Server requires that |
|
202 |
a *shared secret* be used to communicate with the server. This secret is
|
|
203 |
stored in the `magic` variable in the `[usrmgt]` section of |
|
204 |
:file:`/etc/ivle/ivle.conf`. |
|
205 |
||
206 |
The User Management Server is called almost exclusively from the |
|
207 |
:mod:`ivle.webapp.userservice` module. |
|
208 |
||
209 |
See :file:`services/usrmgt-server` for details. |
|
1164.2.37
by David Coles
Chat protocol documentation and some stuff on Console. |
210 |
|
211 |
Chat Protocol
|
|
212 |
=============
|
|
213 |
||
1164.2.38
by David Coles
User Management Server Development Documentation |
214 |
**Chat** is our JSON_-based client/server communication protocol used in
|
1164.2.37
by David Coles
Chat protocol documentation and some stuff on Console. |
215 |
communicating to `Python Console`_ processes and `User Management Server`_. |
216 |
Since it is JSON-based it can be called from either Python or JavaScript. |
|
217 |
||
218 |
Protocol
|
|
219 |
--------
|
|
220 |
The protocol is a fairly simple client/server based one consisting of a single |
|
221 |
JSON object. Before communication starts a shared secret :const:`MAGIC` must |
|
222 |
be known by both parties. The shared secret is then used to form a |
|
223 |
'keyed-Hash Message Authentication Code' to ensure that the content is valid |
|
224 |
and not been modified in transit. |
|
225 |
||
226 |
The client request takes the following form::
|
|
227 |
||
228 |
{
|
|
229 |
"content": DATA,
|
|
230 |
"digest": HASH
|
|
231 |
}
|
|
232 |
||
233 |
where :const:`DATA` is any valid JSON value and :const:`HASH` is an string |
|
234 |
containing the MD5 hash of the :const:`DATA` appended to :const:`MAGIC` and |
|
235 |
then hex encoded. |
|
236 |
||
237 |
The server will respond with a JSON value corresponding to the request. |
|
238 |
If an error occurs then a special JSON object will be returned of the |
|
239 |
following form::
|
|
240 |
||
241 |
{
|
|
242 |
"type": NAME,
|
|
243 |
"value": VALUE,
|
|
244 |
"traceback": TRACEBACK
|
|
245 |
}
|
|
246 |
||
247 |
where :const:`NAME` is a JSON string of the exception type (such as |
|
248 |
'AttributeError'), :const:`VALUE` is the string value associated with the |
|
249 |
exception and :const:`TRACEBACK` is a string of the traceback generated by the |
|
250 |
server's exception handler. |
|
251 |
||
252 |
See :file:`ivle/chat.py` for details. |
|
253 |
||
1164.2.33
by David Coles
Developer Specific system architecture documentation. |
254 |
|
255 |
Version Control
|
|
256 |
===============
|
|
257 |
||
258 |
Worksheets
|
|
259 |
==========
|
|
260 |
||
261 |
Database
|
|
262 |
========
|
|
263 |
||
264 |
.. TODO: Not yet merged
|
|
265 |
Object Publishing
|
|
266 |
=================
|