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 |
|
1336
by David Coles
Subversion developer documentation |
75 |
|
76 |
.. _ref-jail: |
|
77 |
||
1164.2.33
by David Coles
Developer Specific system architecture documentation. |
78 |
Jail System
|
79 |
===========
|
|
80 |
||
81 |
One of the main features of IVLE is it's ability to execute user's code in a |
|
82 |
customised environment that prevents access to other users files or underlying |
|
83 |
file system as well as placing basic resource limits to prevent users from |
|
84 |
accidentally exhausting shared resources such as CPU time and memory. |
|
85 |
||
1164.2.35
by David Coles
More clarification of the jail system |
86 |
|
87 |
Trampoline
|
|
88 |
----------
|
|
89 |
||
1164.2.33
by David Coles
Developer Specific system architecture documentation. |
90 |
To each user, it appears that they have their own private Unix filesystem |
91 |
containing software, libraries and a home directory to do with what they |
|
1336
by David Coles
Subversion developer documentation |
92 |
please. This is mainly done by the setuid root program ``trampoline`` which
|
93 |
mounts the users home directory, sets up the users environment, jumps into the |
|
94 |
user's jail using the :manpage:`chroot(2)` system call and finally drops |
|
95 |
privileges to the desired user and group. |
|
1164.2.33
by David Coles
Developer Specific system architecture documentation. |
96 |
|
97 |
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 |
98 |
specified when trampoline is built by ``setup.py build`` (defaults to UID 33,
|
99 |
www-data on Debian systems). Since it's one of two C programs involved in IVLE |
|
1336
by David Coles
Subversion developer documentation |
100 |
and runs setuid root it is rather security sensitive. |
101 |
||
102 |
.. seealso:: Source code :file:`bin/trampoline/trampoline.c` |
|
103 |
||
1164.2.33
by David Coles
Developer Specific system architecture documentation. |
104 |
|
1164.2.35
by David Coles
More clarification of the jail system |
105 |
Base Image Generation
|
106 |
---------------------
|
|
1164.2.33
by David Coles
Developer Specific system architecture documentation. |
107 |
|
108 |
All user jails share a common base image that contains the files required for |
|
109 |
both IVLE's operation and for executing user code. This base image is |
|
110 |
generated automatically by the ``ivle-buildjail`` script. This then calls the
|
|
111 |
distribution dependant details in :mod:`ivle.jailbuilder` module. At present |
|
112 |
we only support building jails for Debian derived systems using |
|
113 |
:program:`debootstrap`. |
|
114 |
||
115 |
The contents of the base image contains a few core packages required for the |
|
116 |
operation of IVLE - Python and the Python CJSON and SVN libraries. Other |
|
117 |
options that can be configured in :file:`/etc/ivle/ivle.conf` are the file |
|
118 |
mirror that debootstrap should use, the suite to build (such as hardy or |
|
119 |
jaunty), extra apt-sources, extra apt keys and any additional packages to |
|
120 |
install. |
|
121 |
||
122 |
To prevent users from altering files in the base image we change the |
|
123 |
permissions of :file:`/tmp`, :file:`/var/tmp` and :file:`/var/lock` to not be |
|
124 |
world writeable and check that no other files are world writeable. |
|
125 |
||
126 |
Finally we make the user dependent :file:`/etc/passwd` and |
|
127 |
:file:`/etc/ivle/ivle.conf` symlinks to files in the :file:`/home` directory |
|
128 |
so that they will be used when we mount a user's home directory. |
|
129 |
||
130 |
Mounting Home Directories
|
|
131 |
-------------------------
|
|
132 |
||
133 |
To give the appearance of a private file system we need to merge together a |
|
1325
by Matt Giuca
doc/dev/architecture: Moved the discussion of the historical solutions to the mounting problem into a separate note, so the main text just explains the current system. |
134 |
user's local home directory with the base image. |
135 |
To achieve this, IVLE uses the *bind mount* feature of Linux, which allows
|
|
1326
by Matt Giuca
doc/dev/architecture: Reword Mounting Home Directories section (lots of minor edits). Note section reworded as past-tense. |
136 |
directories to be accessible from another location in the file system. By |
137 |
carefully bind-mounting the jail image as read-only and then bind-mounting the |
|
138 |
user's :file:`/home` and :file:`/tmp` directory data over the top, we create a |
|
1336
by David Coles
Subversion developer documentation |
139 |
jail with only three bind mounts and at virtually no file system overhead. |
1164.2.33
by David Coles
Developer Specific system architecture documentation. |
140 |
|
1325
by Matt Giuca
doc/dev/architecture: Moved the discussion of the historical solutions to the mounting problem into a separate note, so the main text just explains the current system. |
141 |
.. note:: |
142 |
IVLE has historically used numerous solutions to this problem, which are |
|
143 |
chronicled here to avoid the same mistakes being made again. |
|
144 |
||
1326
by Matt Giuca
doc/dev/architecture: Reword Mounting Home Directories section (lots of minor edits). Note section reworded as past-tense. |
145 |
In the first release of IVLE this was done offline by hard-linking all the |
146 |
files into the target directory, but for a large number of users, this |
|
147 |
process can take several hours, and also runs the risk of exhausting |
|
148 |
the number of inodes on the underlying file system. |
|
1325
by Matt Giuca
doc/dev/architecture: Moved the discussion of the historical solutions to the mounting problem into a separate note, so the main text just explains the current system. |
149 |
|
1326
by Matt Giuca
doc/dev/architecture: Reword Mounting Home Directories section (lots of minor edits). Note section reworded as past-tense. |
150 |
The second solution was to use `AUFS <http://aufs.sourceforge.net/>`_ to |
1325
by Matt Giuca
doc/dev/architecture: Moved the discussion of the historical solutions to the mounting problem into a separate note, so the main text just explains the current system. |
151 |
mount the user's home directory over a read-only version of the base on |
152 |
demand. This was implemented as part of ``trampoline`` and used a secondary
|
|
1326
by Matt Giuca
doc/dev/architecture: Reword Mounting Home Directories section (lots of minor edits). Note section reworded as past-tense. |
153 |
program ``timount`` (see :file:`bin/timount/timount.c`), run at regular |
154 |
intervals, to unmount unused jails. This used the :const:`MNT_EXPIRE` flag |
|
1325
by Matt Giuca
doc/dev/architecture: Moved the discussion of the historical solutions to the mounting problem into a separate note, so the main text just explains the current system. |
155 |
for :manpage:`umount(2)` (available since Linux 2.6.8) that only unmounts a |
156 |
directory if it hasn't been accessed since the previous call with |
|
157 |
:const:`MNT_EXPIRE`. |
|
158 |
||
1326
by Matt Giuca
doc/dev/architecture: Reword Mounting Home Directories section (lots of minor edits). Note section reworded as past-tense. |
159 |
While quite effective, AUFS appeared to cause NFS caching issues when IVLE |
160 |
was run as a cluster, and as its inclusion status in future Linux |
|
161 |
distributions is questionable, the developers elected to use the much older |
|
162 |
bind mount feature instead. |
|
1325
by Matt Giuca
doc/dev/architecture: Moved the discussion of the historical solutions to the mounting problem into a separate note, so the main text just explains the current system. |
163 |
|
1164.2.33
by David Coles
Developer Specific system architecture documentation. |
164 |
Entering the Jail
|
165 |
-----------------
|
|
166 |
||
167 |
Before running the specified program in the users jail we need to |
|
168 |
:manpage:`chroot(2)` into the users jail and update the processes environment |
|
169 |
so that we have the correct environment variables and user/group ids. |
|
170 |
||
171 |
At this stage we also may apply a number of resource limits (see |
|
172 |
:manpage:`setrlimit`) to prevent run away processes (such as those containing |
|
173 |
infinite loops or "fork bombs") from exhausting all system resources. The |
|
174 |
default limits are on maximum address space (:const:`RLIMIT_AS`), process data |
|
175 |
space (:const:`RLIMIT_DATA`), core dump size (:const:`RLIMIT_CORE`), CPU time |
|
176 |
(:const:`RLIMIT_CPU`), file size (:const:`RLIMIT_FSIZE`) and number of |
|
177 |
processes that may be spawned (:const:`RLIMIT_NPROC`). |
|
178 |
||
179 |
Unfortunately due to glibc's :manpage:`malloc(2)` implementation being able to |
|
180 |
allocate memory using :manpage:`mmap(2)`, :const:`RLIMIT_DATA` does not |
|
181 |
provide an effective limit on the amount of memory that a process can allocate |
|
182 |
(short of applying a kernel patch). Thus the only way to limit memory |
|
183 |
allocations is by placing limits on the address space, but this can cause |
|
184 |
problems with certain applications that allocate far larger address spaces |
|
185 |
than the real memory used. For this reason :const:`RLIMIT_AS` is currently set |
|
186 |
very large. |
|
187 |
||
1336
by David Coles
Subversion developer documentation |
188 |
|
1468
by Matt Giuca
doc/dev/architecture: Fixed reference (ref-python-console). |
189 |
.. _ref-python-console: |
1336
by David Coles
Subversion developer documentation |
190 |
|
1164.2.37
by David Coles
Chat protocol documentation and some stuff on Console. |
191 |
Python Console
|
192 |
==============
|
|
193 |
||
194 |
IVLE provides a web based programming console, exposing similar features to |
|
1463
by William Grant
Expand console architecture documentation to explain the rather odd communication method. |
195 |
Python's command line console. It is built around the |
196 |
:file:`services/python-console` script, which opens up a socket on a random |
|
197 |
port to which `JSON`_ encoded chat requests can be made.
|
|
198 |
||
199 |
A new console is typically launched on demand by the web client to the HTTP |
|
200 |
API, which in turn calls the wrapper class :class:`ivle.console.Console` to |
|
201 |
start a new console in the user's jail. |
|
202 |
||
203 |
Subsequent requests from the same in-browser console connect to the existing |
|
204 |
console process. This is achieved by storing a string on the client which |
|
205 |
identifies the server address and port. The client then makes requests |
|
206 |
through the load balancer, sending this string through to an arbitrary slave |
|
207 |
which forwards the request to the identified console. |
|
208 |
||
209 |
This means that all slaves need access to all ports on every other slave. |
|
1164.2.37
by David Coles
Chat protocol documentation and some stuff on Console. |
210 |
|
211 |
.. _JSON: http://json.org |
|
212 |
||
1336
by David Coles
Subversion developer documentation |
213 |
|
1418
by Matt Giuca
doc/dev/architecture: s/usermgt/usrmgt/g. Some references to usrmgt already existed (which are now fixed). usrmgt appears to be this service's canonical name in the source code. |
214 |
.. _ref-usrmgt-server: |
1336
by David Coles
Subversion developer documentation |
215 |
|
1164.2.37
by David Coles
Chat protocol documentation and some stuff on Console. |
216 |
User Management Server
|
217 |
======================
|
|
218 |
||
1164.2.38
by David Coles
User Management Server Development Documentation |
219 |
The **User Management Server** is a daemon responsible for handling privileged
|
220 |
actions on IVLE and should be launched along with IVLE. It is primarily |
|
221 |
responsible for: |
|
222 |
||
223 |
* Creating user jails, Subversion repositories, and Subversion authentication
|
|
224 |
credentials. |
|
225 |
* Creating group Subversion repositories.
|
|
226 |
* Rebuilding Subversion authorization files.
|
|
227 |
||
1414
by Matt Giuca
docs: dev/architecture and man/config: Replaced `name`_ style internal links |
228 |
Communication with the Server is done using the :ref:`Chat Protocol |
229 |
<ref-chat>`. To prevent unauthorized use, communication with the User
|
|
230 |
Management Server requires that a *shared secret* be used to communicate with
|
|
231 |
the server. This secret is stored in the `magic` variable in the `[usrmgt]` |
|
232 |
section of :file:`/etc/ivle/ivle.conf`. |
|
1164.2.38
by David Coles
User Management Server Development Documentation |
233 |
|
234 |
The User Management Server is called almost exclusively from the |
|
235 |
:mod:`ivle.webapp.userservice` module. |
|
236 |
||
1336
by David Coles
Subversion developer documentation |
237 |
.. seealso:: Source code :file:`services/usrmgt-server` |
238 |
||
239 |
.. _ref-chat: |
|
1164.2.37
by David Coles
Chat protocol documentation and some stuff on Console. |
240 |
|
241 |
Chat Protocol
|
|
242 |
=============
|
|
243 |
||
1414
by Matt Giuca
docs: dev/architecture and man/config: Replaced `name`_ style internal links |
244 |
**Chat** is our JSON_-based client/server communication protocol used in
|
245 |
communicating to :ref:`Python Console <ref-python-console>` processes and |
|
246 |
:ref:`User Management Server <ref-usrmgt-server>`. Since it is JSON-based it |
|
247 |
can be called from either Python or JavaScript. |
|
1164.2.37
by David Coles
Chat protocol documentation and some stuff on Console. |
248 |
|
249 |
Protocol
|
|
250 |
--------
|
|
251 |
The protocol is a fairly simple client/server based one consisting of a single |
|
252 |
JSON object. Before communication starts a shared secret :const:`MAGIC` must |
|
253 |
be known by both parties. The shared secret is then used to form a |
|
254 |
'keyed-Hash Message Authentication Code' to ensure that the content is valid |
|
255 |
and not been modified in transit. |
|
256 |
||
257 |
The client request takes the following form::
|
|
258 |
||
259 |
{
|
|
260 |
"content": DATA,
|
|
261 |
"digest": HASH
|
|
262 |
}
|
|
263 |
||
264 |
where :const:`DATA` is any valid JSON value and :const:`HASH` is an string |
|
265 |
containing the MD5 hash of the :const:`DATA` appended to :const:`MAGIC` and |
|
266 |
then hex encoded. |
|
267 |
||
268 |
The server will respond with a JSON value corresponding to the request. |
|
269 |
If an error occurs then a special JSON object will be returned of the |
|
270 |
following form::
|
|
271 |
||
272 |
{
|
|
273 |
"type": NAME,
|
|
274 |
"value": VALUE,
|
|
275 |
"traceback": TRACEBACK
|
|
276 |
}
|
|
277 |
||
278 |
where :const:`NAME` is a JSON string of the exception type (such as |
|
279 |
'AttributeError'), :const:`VALUE` is the string value associated with the |
|
280 |
exception and :const:`TRACEBACK` is a string of the traceback generated by the |
|
281 |
server's exception handler. |
|
282 |
||
1336
by David Coles
Subversion developer documentation |
283 |
.. seealso:: Source code :file:`ivle/chat.py` |
1164.2.37
by David Coles
Chat protocol documentation and some stuff on Console. |
284 |
|
1164.2.33
by David Coles
Developer Specific system architecture documentation. |
285 |
|
286 |
Version Control
|
|
287 |
===============
|
|
288 |
||
1336
by David Coles
Subversion developer documentation |
289 |
Along with traditional file system access, IVLE allows users to version their |
290 |
files using Subversion_. Much like how Subversion workspaces are used on a |
|
291 |
standard desktop, workspaces are checked out into users home directories where |
|
292 |
they can be manipulated through a series of AJAX requests to the |
|
293 |
``fileservice`` app.
|
|
294 |
||
295 |
Like all other user file system actions, version control actions need to be |
|
296 |
executed inside the user's :ref:`jail <ref-jail>`. Requests are made to the |
|
297 |
``fileservice`` app in :mod:`ivle.webapp.fileservice` which then calls the |
|
298 |
``fileservice`` CGI script using ``trampoline``. This script is simply a |
|
299 |
wrapper around :mod:`ivle.fileservice_lib` which actually contains the code to |
|
300 |
handle each of the actions. |
|
301 |
||
302 |
Manipulation of the Subversion workspaces is done using the pysvn_ library. |
|
303 |
||
304 |
.. _Subversion: http://subversion.tigris.org/ |
|
305 |
.. _pysvn: http://pysvn.tigris.org/ |
|
306 |
||
307 |
||
308 |
Repositories
|
|
309 |
------------
|
|
310 |
||
311 |
Each user is allocated a Subversion repository when their :ref:`Jail |
|
312 |
<ref-jail>` is created by the :ref:`User Management Server |
|
1418
by Matt Giuca
doc/dev/architecture: s/usermgt/usrmgt/g. Some references to usrmgt already existed (which are now fixed). usrmgt appears to be this service's canonical name in the source code. |
313 |
<ref-usrmgt-server>`. Repository are stored in the location specified by
|
1336
by David Coles
Subversion developer documentation |
314 |
``[paths] [[svn]] repo_path`` in :file:`/etc/ivle/ivle.conf` (by default |
315 |
:file:`/var/lib/ivle/svn/repositories/`). User repositories are stored in the |
|
316 |
:samp:`users/{USERNAME}/` subdirectory and group repositories in |
|
317 |
:samp:`groups/{SUBJECT}_{YEAR}_{SEMESTER}_{GROUP}`. |
|
318 |
||
319 |
.. warning:: |
|
320 |
||
321 |
While it would be possible to give users direct access to their repository |
|
322 |
using Subversion's file backend, this would allow users to potentially |
|
323 |
modify the history of any repository that they had access to. To ensure |
|
324 |
repository integrity, all Subversion interaction must be done remotely. |
|
325 |
||
326 |
||
327 |
Subversion WebDAV
|
|
328 |
-----------------
|
|
329 |
||
330 |
These repositories are served by Apache using ``mod_dav_svn`` allowing access
|
|
331 |
over Subversion's WebDAV HTTP or HTTPS backends. Users are authenticated using |
|
332 |
a randomly generated key which is stored in the database and is made available |
|
333 |
to each user inside their Jail (``svn_pass`` property inside
|
|
334 |
:file:`/home/.ivle.conf`). This key is automatically provided when doing |
|
335 |
Subversion actions, but can be manually entered when accessing a users |
|
336 |
repository from an external Subversion client such as with :samp:`svn checkout |
|
337 |
{svn_addr}/users/{USERNAME}/ workspace`. |
|
338 |
||
339 |
Repository permissions for ``AuthzSVNAccessFILE`` are automatically generated
|
|
340 |
and placed in the file located at ``[paths] [[svn]] conf`` for user
|
|
341 |
repositories and ``[paths] [[svn]] group_conf`` for group repositories. User
|
|
342 |
authentication keys for ``AuthUserFile`` are stored in the file located at
|
|
343 |
``[path] [[svn]] auth_ivle``. These will be regenerated each time user or
|
|
344 |
group repository settings change. |
|
345 |
||
346 |
||
1164.2.33
by David Coles
Developer Specific system architecture documentation. |
347 |
Worksheets
|
348 |
==========
|
|
349 |
||
350 |
Database
|
|
351 |
========
|
|
352 |
||
353 |
.. TODO: Not yet merged
|
|
354 |
Object Publishing
|
|
355 |
=================
|