~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to setup/configure.py

Added module ivle.config, which takes care of some work interfacing with
    configobj, including searching for the file and opening the object.
ivle.conf.conf now uses this instead of having its own search.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
# Module: setup/config
 
19
# Author: Matt Giuca, Refactored by David Coles
 
20
# Date:   03/07/2008
 
21
 
 
22
'''Configures IVLE with machine-specific details, most notably, various paths.
 
23
Either prompts the administrator for these details or accepts them as
 
24
command-line args.
 
25
 
 
26
Creates ivle/conf/conf.py and bin/trampoline/trampoline/conf.h.
 
27
'''
 
28
 
 
29
import optparse
 
30
import getopt
 
31
import os
 
32
import sys
 
33
import hashlib
 
34
import uuid
 
35
 
 
36
from setup.util import query_user
 
37
 
 
38
import configobj
 
39
 
 
40
# This dict maps legacy config option names to new config option paths
 
41
# ('section/option_name')
 
42
# NOTE: This is copied from ivle/conf/conf.py (because neither of these files
 
43
# can see each other).
 
44
CONFIG_OPTIONS = {
 
45
    'root_dir': 'urls/root',
 
46
    'prefix': 'paths/prefix',
 
47
    'data_path': 'paths/data',
 
48
    'log_path': 'paths/logs',
 
49
    'python_site_packages_override': 'paths/site_packages',
 
50
    'public_host': 'urls/public_host',
 
51
    'allowed_uids': 'os/allowed_uids',
 
52
    'db_host': 'database/host',
 
53
    'db_port': 'database/port',
 
54
    'db_dbname': 'database/name',
 
55
    'db_forumdbname': 'plugins/forum/dbname',
 
56
    'db_user': 'database/username',
 
57
    'db_password': 'database/password',
 
58
    'auth_modules': 'auth/modules',
 
59
    'ldap_url': 'auth/ldap_url',
 
60
    'ldap_format_string': 'auth/ldap_format_string',
 
61
    'subject_pulldown_modules': 'auth/subject_pulldown_modules',
 
62
    'svn_addr': 'urls/svn_addr',
 
63
    'usrmgt_host': 'usrmgt/host',
 
64
    'usrmgt_port': 'usrmgt/port',
 
65
    'usrmgt_magic': 'usrmgt/magic',
 
66
    'forum_secret': 'plugins/forum/secret',
 
67
}
 
68
 
 
69
class ConfigOption:
 
70
    """A configuration option; one of the things written to conf.py."""
 
71
    def __init__(self, option_name, default, prompt, comment, ask=True):
 
72
        """Creates a configuration option.
 
73
        option_name: Name of the variable in conf.py. Also name of the
 
74
            command-line argument to setup.py conf.
 
75
        default: Default value for this variable.
 
76
        prompt: (Short) string presented during the interactive prompt in
 
77
            setup.py conf.
 
78
        comment: (Long) comment string stored in conf.py. Each line of this
 
79
            string should begin with a '#'.
 
80
        ask: Whether to ask the question in the default config run.
 
81
        """
 
82
        self.option_name = option_name
 
83
        self.default = default
 
84
        self.prompt = prompt
 
85
        self.comment = comment
 
86
        self.ask = ask
 
87
 
 
88
# Configuration options, defaults and descriptions
 
89
config_options = []
 
90
 
 
91
config_options.append(ConfigOption("root_dir", "/",
 
92
    """Root directory where IVLE is located (in URL space):""",
 
93
    """
 
94
# In URL space, where in the site is IVLE located. (All URLs will be prefixed
 
95
# with this).
 
96
# eg. "/" or "/ivle".""", ask=False))
 
97
 
 
98
config_options.append(ConfigOption("prefix", "/usr/local",
 
99
    """In the local file system, the prefix to the system directory where IVLE
 
100
is installed. (This should either be /usr or /usr/local):""",
 
101
    """
 
102
# In the local file system, the prefix to the system directory where IVLE is
 
103
# installed. This should either be '/usr' or '/usr/local'.
 
104
# ('/usr/local' for the usual install, '/usr' for distribution packages)""",
 
105
    ask=False))
 
106
 
 
107
config_options.append(ConfigOption("python_site_packages_override",
 
108
    None,
 
109
    """site-packages directory in Python, where Python libraries are to be
 
110
installed. May be left as the default, in which case the value will be
 
111
computed from prefix and the current Python version:""",
 
112
    """
 
113
# 'site-packages' directory in Python, where Python libraries are to be
 
114
# installed. May be None (recommended), in which case the value will be
 
115
# computed from prefix and the current Python version.""", ask=False))
 
116
 
 
117
config_options.append(ConfigOption("data_path",
 
118
    "/var/lib/ivle",
 
119
    "In the local file system, where user-modifiable data files should be "
 
120
    "located:",
 
121
    """
 
122
# In the local file system, where user-modifiable data files should be
 
123
# located.""", ask=False))
 
124
 
 
125
config_options.append(ConfigOption("log_path",
 
126
    "/var/log/ivle",
 
127
    """Directory where IVLE log files are stored (on the local
 
128
file system). Note - this must be writable by the user the IVLE server 
 
129
process runs as (usually www-data):""",
 
130
    """
 
131
# In the local file system, where IVLE error logs should be located.""",
 
132
    ask=False))
 
133
 
 
134
config_options.append(ConfigOption("public_host", "public.localhost",
 
135
    """Hostname which will cause the server to go into "public mode",
 
136
providing login-free access to student's published work:""",
 
137
    """
 
138
# The server goes into "public mode" if the browser sends a request with this
 
139
# host. This is for security reasons - we only serve public student files on a
 
140
# separate domain to the main IVLE site.
 
141
# Public mode does not use cookies, and serves only public content.
 
142
# Private mode (normal mode) requires login, and only serves files relevant to
 
143
# the logged-in user."""))
 
144
 
 
145
config_options.append(ConfigOption("allowed_uids", "33",
 
146
    """UID of the web server process which will run IVLE.
 
147
Only this user may execute the trampoline. May specify multiple users as
 
148
a comma-separated list.
 
149
    (eg. "1002,78")""",
 
150
    """
 
151
# The User-ID of the web server process which will run IVLE, and any other
 
152
# users who are allowed to run the trampoline. This is stores as a string of
 
153
# comma-separated integers, simply because it is not used within Python, only
 
154
# used by the setup program to write to conf.h (see setup.py config).""",
 
155
    ask=False))
 
156
 
 
157
config_options.append(ConfigOption("db_host", "localhost",
 
158
    """PostgreSQL Database config
 
159
==========================
 
160
Hostname of the DB server:""",
 
161
    """
 
162
# Database server hostname"""))
 
163
 
 
164
config_options.append(ConfigOption("db_port", "5432",
 
165
    """Port of the DB server:""",
 
166
    """
 
167
# Database server port"""))
 
168
 
 
169
config_options.append(ConfigOption("db_dbname", "ivle",
 
170
    """Database name:""",
 
171
    """
 
172
# Database name"""))
 
173
 
 
174
config_options.append(ConfigOption("db_forumdbname", "ivle_forum",
 
175
    """Forum Database name:""",
 
176
    """
 
177
# Forum Database name"""))
 
178
 
 
179
config_options.append(ConfigOption("db_user", "postgres",
 
180
    """Username for DB server login:""",
 
181
    """
 
182
# Database username"""))
 
183
 
 
184
config_options.append(ConfigOption("db_password", "",
 
185
    """Password for DB server login:
 
186
    (Caution: This password is stored in plaintext in ivle/conf/conf.py)""",
 
187
    """
 
188
# Database password"""))
 
189
 
 
190
config_options.append(ConfigOption("auth_modules", "",
 
191
    """Authentication config
 
192
=====================
 
193
Comma-separated list of authentication modules.""",
 
194
    """
 
195
# Comma-separated list of authentication modules.
 
196
# Note that auth is always enabled against the local database, and NO OTHER
 
197
# auth is enabled by default. This section is for specifying additional auth
 
198
# modules.
 
199
# These refer to importable Python modules in the www/auth directory.
 
200
# Modules "ldap_auth" and "guest" are available in the source tree, but
 
201
# other modules may be plugged in to auth against organisation-specific
 
202
# auth backends.""", ask=False))
 
203
 
 
204
config_options.append(ConfigOption("ldap_url", "ldaps://www.example.com",
 
205
    """(LDAP options are only relevant if "ldap" is included in the list of
 
206
auth modules).
 
207
URL for LDAP authentication server:""",
 
208
    """
 
209
# URL for LDAP authentication server""", ask=False))
 
210
 
 
211
config_options.append(ConfigOption("ldap_format_string",
 
212
    "uid=%s,ou=users,o=example",
 
213
    """Format string for LDAP auth request:
 
214
    (Must contain a single "%s" for the user's login name)""",
 
215
    """
 
216
# Format string for LDAP auth request
 
217
# (Must contain a single "%s" for the user's login name)""", ask=False))
 
218
 
 
219
config_options.append(ConfigOption("subject_pulldown_modules", "",
 
220
    """Comma-separated list of subject pulldown modules.
 
221
Add proprietary modules to automatically enrol students in subjects.""",
 
222
    """
 
223
# Comma-separated list of subject pulldown modules.
 
224
# These refer to importable Python modules in the lib/pulldown_subj directory.
 
225
# Only "dummy_subj" is available in the source tree (an example), but
 
226
# other modules may be plugged in to pulldown against organisation-specific
 
227
# pulldown backends.""", ask=False))
 
228
 
 
229
config_options.append(ConfigOption("svn_addr", "http://svn.localhost/",
 
230
    """Subversion config
 
231
=================
 
232
The base url for accessing subversion repositories:""",
 
233
    """
 
234
# The base url for accessing subversion repositories."""))
 
235
 
 
236
config_options.append(ConfigOption("usrmgt_host", "localhost",
 
237
    """User Management Server config
 
238
============================
 
239
The hostname where the usrmgt-server runs:""",
 
240
    """
 
241
# The hostname where the usrmgt-server runs."""))
 
242
 
 
243
config_options.append(ConfigOption("usrmgt_port", "2178",
 
244
    """The port where the usrmgt-server runs:""",
 
245
    """
 
246
# The port where the usrmgt-server runs.""", ask=False))
 
247
 
 
248
config_options.append(ConfigOption("usrmgt_magic", None,
 
249
    """The password for the usrmgt-server:""",
 
250
    """
 
251
# The password for the usrmgt-server.""", ask=False))
 
252
 
 
253
def configure(args):
 
254
    # Call the real function
 
255
    return __configure(args)
 
256
 
 
257
def __configure(args):
 
258
    global db_port, usrmgt_port
 
259
 
 
260
    # Try importing existing conf, but if we can't just set up defaults
 
261
    # The reason for this is that these settings are used by other phases
 
262
    # of setup besides conf, so we need to know them.
 
263
    # Also this allows you to hit Return to accept the existing value.
 
264
    try:
 
265
        confmodule = __import__("ivle/conf/conf")
 
266
        for opt in config_options:
 
267
            try:
 
268
                globals()[opt.option_name] = \
 
269
                confmodule.__dict__[opt.option_name]
 
270
            except:
 
271
                globals()[opt.option_name] = opt.default
 
272
    except ImportError:
 
273
        # Just set reasonable defaults
 
274
        for opt in config_options:
 
275
            globals()[opt.option_name] = opt.default
 
276
 
 
277
    # Set up some variables
 
278
    cwd = os.getcwd()
 
279
 
 
280
    # the files that will be created/overwritten
 
281
    conffile = os.path.join(cwd, "etc/ivle.conf")
 
282
    conf_hfile = os.path.join(cwd, "bin/trampoline/conf.h")
 
283
    phpBBconffile = os.path.join(cwd, "www/php/phpBB3/config.php")
 
284
 
 
285
    # Get command-line arguments to avoid asking questions.
 
286
 
 
287
    optnames = []
 
288
    for opt in config_options:
 
289
        optnames.append(opt.option_name + "=")
 
290
    (opts, args) = getopt.gnu_getopt(args, "", optnames)
 
291
 
 
292
    if args != []:
 
293
        print >>sys.stderr, "Invalid arguments:", string.join(args, ' ')
 
294
        return 2
 
295
 
 
296
    if opts == []:
 
297
        # Interactive mode. Prompt the user for all the values.
 
298
 
 
299
        print """This tool will create the following files:
 
300
    %s
 
301
    %s
 
302
    %s
 
303
prompting you for details about your configuration. The file will be
 
304
overwritten if it already exists. It will *not* install or deploy IVLE.
 
305
 
 
306
Please hit Ctrl+C now if you do not wish to do this.
 
307
""" % (conffile, conf_hfile, phpBBconffile)
 
308
 
 
309
        # Get information from the administrator
 
310
        # If EOF is encountered at any time during the questioning, just exit
 
311
        # silently
 
312
 
 
313
        for opt in config_options:
 
314
            if opt.ask:
 
315
                globals()[opt.option_name] = \
 
316
                    query_user(globals()[opt.option_name], opt.prompt)
 
317
    else:
 
318
        opts = dict(opts)
 
319
        # Non-interactive mode. Parse the options.
 
320
        for opt in config_options:
 
321
            if '--' + opt.option_name in opts:
 
322
                globals()[opt.option_name] = opts['--' + opt.option_name]
 
323
 
 
324
    # Error handling on input values
 
325
    try:
 
326
        allowed_uids_list = map(int, allowed_uids.split(','))
 
327
    except ValueError:
 
328
        print >>sys.stderr, (
 
329
        "Invalid UID list (%s).\n"
 
330
        "Must be a comma-separated list of integers." % allowed_uids)
 
331
        return 1
 
332
    try:
 
333
        db_port = int(db_port)
 
334
        if db_port < 0 or db_port >= 65536: raise ValueError()
 
335
    except ValueError:
 
336
        print >>sys.stderr, (
 
337
        "Invalid DB port (%s).\n"
 
338
        "Must be an integer between 0 and 65535." % repr(db_port))
 
339
        return 1
 
340
    try:
 
341
        usrmgt_port = int(usrmgt_port)
 
342
        if usrmgt_port < 0 or usrmgt_port >= 65536: raise ValueError()
 
343
    except ValueError:
 
344
        print >>sys.stderr, (
 
345
        "Invalid user management port (%s).\n"
 
346
        "Must be an integer between 0 and 65535." % repr(usrmgt_port))
 
347
        return 1
 
348
 
 
349
    # By default we generate the magic randomly.
 
350
    if globals()['usrmgt_magic'] is None:
 
351
        globals()['usrmgt_magic'] = hashlib.md5(uuid.uuid4().bytes).hexdigest()
 
352
 
 
353
    # Generate the forum secret
 
354
    forum_secret = hashlib.md5(uuid.uuid4().bytes).hexdigest()
 
355
 
 
356
    # Write ./etc/ivle.conf
 
357
 
 
358
    conf = configobj.ConfigObj()
 
359
    conf.filename = conffile
 
360
 
 
361
    conf.initial_comment = ["# IVLE Configuration File"]
 
362
 
 
363
    # Add the forum secret to the config file (regenerated each config)
 
364
    config_options.append(ConfigOption('forum_secret', None, '', ''))
 
365
    globals()['forum_secret'] = forum_secret
 
366
 
 
367
    for legacyopt in config_options:
 
368
        newopt_path = CONFIG_OPTIONS[legacyopt.option_name].split('/')
 
369
        # Iterate over each segment of the path, and find the section in conf
 
370
        # file to insert the value into (use all but the last path segment)
 
371
        conf_section = conf
 
372
        for seg in newopt_path[:-1]:
 
373
            # Create the section if it isn't there
 
374
            if seg not in conf_section:
 
375
                conf_section[seg] = {}
 
376
            conf_section = conf_section[seg]
 
377
        # The final path segment names the key to insert into
 
378
        keyname = newopt_path[-1]
 
379
        value = globals()[legacyopt.option_name]
 
380
        if value is not None:
 
381
            conf_section[keyname] = value
 
382
            conf_section.comments[keyname] = legacyopt.comment.split('\n')
 
383
 
 
384
    conf.write()
 
385
 
 
386
    print "Successfully wrote %s" % conffile
 
387
 
 
388
    # Write bin/trampoline/conf.h
 
389
 
 
390
    conf = open(conf_hfile, "w")
 
391
 
 
392
    # XXX Compute jail_base, jail_src_base and jail_system. These will
 
393
    # ALSO be done by the boilerplate code, but we need them here in order
 
394
    # to write to the C file.
 
395
    jail_base = os.path.join(data_path, 'jailmounts')
 
396
    jail_src_base = os.path.join(data_path, 'jails')
 
397
    jail_system = os.path.join(jail_src_base, '__base__')
 
398
 
 
399
    conf.write("""/* IVLE Configuration File
 
400
 * conf.h
 
401
 * Administrator settings required by trampoline.
 
402
 * Note: trampoline will have to be rebuilt in order for changes to this file
 
403
 * to take effect.
 
404
 */
 
405
 
 
406
#define IVLE_AUFS_JAILS
 
407
 
 
408
/* In the local file system, where are the jails located.
 
409
 * The trampoline does not allow the creation of a jail anywhere besides
 
410
 * jail_base or a subdirectory of jail_base.
 
411
 */
 
412
static const char* jail_base = "%s";
 
413
static const char* jail_src_base = "%s";
 
414
static const char* jail_system = "%s";
 
415
 
 
416
/* Which user IDs are allowed to run the trampoline.
 
417
 * This list should be limited to the web server user.
 
418
 * (Note that root is an implicit member of this list).
 
419
 */
 
420
static const int allowed_uids[] = { %s };
 
421
""" % (repr(jail_base)[1:-1], repr(jail_src_base)[1:-1],
 
422
       repr(jail_system)[1:-1], repr(allowed_uids_list)[1:-1]))
 
423
    # Note: The above uses PYTHON reprs, not C reprs
 
424
    # However they should be the same with the exception of the outer
 
425
    # characters, which are stripped off and replaced
 
426
 
 
427
    conf.close()
 
428
 
 
429
    print "Successfully wrote %s" % conf_hfile
 
430
 
 
431
    # Write www/php/phpBB3/config.php
 
432
 
 
433
    conf = open(phpBBconffile, "w")
 
434
    
 
435
    # php-pg work around
 
436
    if db_host == 'localhost':
 
437
        forumdb_host = '127.0.0.1'
 
438
    else:
 
439
        forumdb_host = db_host
 
440
 
 
441
    conf.write( """<?php
 
442
// phpBB 3.0.x auto-generated configuration file
 
443
// Do not change anything in this file!
 
444
$dbms = 'postgres';
 
445
$dbhost = '""" + forumdb_host + """';
 
446
$dbport = '""" + str(db_port) + """';
 
447
$dbname = '""" + db_forumdbname + """';
 
448
$dbuser = '""" + db_user + """';
 
449
$dbpasswd = '""" + db_password + """';
 
450
 
 
451
$table_prefix = 'phpbb_';
 
452
$acm_type = 'file';
 
453
$load_extensions = '';
 
454
@define('PHPBB_INSTALLED', true);
 
455
// @define('DEBUG', true);
 
456
//@define('DEBUG_EXTRA', true);
 
457
 
 
458
$forum_secret = '""" + forum_secret +"""';
 
459
?>"""   )
 
460
    
 
461
    conf.close()
 
462
 
 
463
    print "Successfully wrote %s" % phpBBconffile
 
464
 
 
465
    print
 
466
    print "You may modify the configuration at any time by editing"
 
467
    print conffile
 
468
    print conf_hfile
 
469
    print phpBBconffile
 
470
    print
 
471
    
 
472
    return 0