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

« back to all changes in this revision

Viewing changes to lib/common/makeuser.py

  • Committer: drtomc
  • Date: 2008-03-06 02:32:37 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:659
Add a little script for stuffing exercises into the database.

Add an identifier field to the problem table.

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
 
32
32
# TODO: When creating a new home directory, chown it to its owner
33
33
 
34
 
# TODO: In chown_to_webserver:
35
 
# Do not call os.system("chown www-data") - use Python lib
36
 
# and use the web server uid given in conf. (Several places).
37
 
 
38
34
import md5
39
35
import os
40
36
import stat
42
38
import time
43
39
import uuid
44
40
import warnings
45
 
import filecmp
 
41
 
46
42
import conf
47
43
import db
48
44
 
49
 
def chown_to_webserver(filename):
50
 
    """
51
 
    Chowns a file so the web server user owns it.
52
 
    (This is useful in setting up Subversion conf files).
53
 
    Assumes root.
54
 
    """
55
 
    try:
56
 
        os.system("chown -R www-data:www-data %s" % filename)
57
 
    except:
58
 
        pass
59
 
 
60
45
def make_svn_repo(login, throw_on_error=True):
61
46
    """Create a repository for the given user.
62
47
    """
69
54
        print repr(exc)
70
55
        if throw_on_error:
71
56
            raise
72
 
 
73
 
    chown_to_webserver(path)
 
57
    try:
 
58
        os.system("chown -R www-data:www-data %s" % path)
 
59
    except Exception:
 
60
        pass
74
61
 
75
62
def rebuild_svn_config():
76
63
    """Build the complete SVN configuration file.
101
88
        f.write("\n")
102
89
    f.close()
103
90
    os.rename(conf.svn_conf + ".new", conf.svn_conf)
104
 
    chown_to_webserver(conf.svn_conf)
105
91
 
106
92
def make_svn_config(login, throw_on_error=True):
107
93
    """Add an entry to the apache-svn config file for the given user.
115
101
    #f.write("@admin = rw\n")
116
102
    f.write("\n")
117
103
    f.close()
118
 
    chown_to_webserver(conf.svn_conf)
119
104
 
120
105
def make_svn_auth(login, throw_on_error=True):
121
106
    """Setup svn authentication for the given user.
135
120
    if res != 0 and throw_on_error:
136
121
        raise Exception("Unable to create ivle-auth for %s" % login)
137
122
 
138
 
    # Make sure the file is owned by the web server
139
 
    if create == "c":
140
 
        chown_to_webserver(conf.svn_auth_ivle)
141
 
 
142
123
    return passwd
143
124
 
144
 
def generate_manifest(basedir, targetdir, parent=''):
145
 
    """ From a basedir and a targetdir work out which files are missing or out 
146
 
    of date and need to be added/updated and which files are redundant and need 
147
 
    to be removed.
148
 
    
149
 
    parent: This is used for the recursive call to track the relative paths 
150
 
    that we have decended.
151
 
    """
152
 
    
153
 
    cmp = filecmp.dircmp(basedir, targetdir)
154
 
 
155
 
    # Add all new files and files that have changed
156
 
    to_add = [os.path.join(parent,x) for x in (cmp.left_only + cmp.diff_files)]
157
 
 
158
 
    # Remove files that are redundant
159
 
    to_remove = [os.path.join(parent,x) for x in cmp.right_only]
160
 
    
161
 
    # Recurse
162
 
    for d in cmp.common_dirs:
163
 
        newbasedir = os.path.join(basedir, d)
164
 
        newtargetdir = os.path.join(targetdir, d)
165
 
        newparent = os.path.join(parent, d)
166
 
        (sadd,sremove) = generate_manifest(newbasedir, newtargetdir, newparent)
167
 
        to_add += sadd
168
 
        to_remove += sremove
169
 
 
170
 
    return (to_add, to_remove)
171
 
 
172
 
 
173
 
def make_jail(username, uid, force=True, manifest=None, svn_pass=None):
 
125
def make_jail(username, uid, force=True):
174
126
    """Creates a new user's jail space, in the jail directory as configured in
175
127
    conf.py.
176
128
 
177
 
    This expects there to be a "staging" directory within the jail root which
 
129
    This expects there to be a "template" directory within the jail root which
178
130
    contains all the files for a sample student jail. It creates the student's
179
131
    directory in the jail root, by making a hard-link copy of every file in the
180
 
    staging directory, recursively.
 
132
    template directory, recursively.
181
133
 
182
134
    Returns the path to the user's home directory.
183
135
 
190
142
 
191
143
    force: If false, exception if jail already exists for this user.
192
144
    If true (default), overwrites it, but preserves home directory.
193
 
 
194
 
    manifest: If provided this will be a pair (to_add, to_remove) of files or
195
 
    directories to add or remove from the jail.
196
 
 
197
 
    svn_pass: If provided this will be a string, the randomly-generated
198
 
    Subversion password for this user (if you happen to already have it).
199
 
    If not provided, it will be read from the database.
200
145
    """
201
146
    # MUST run as root or some of this may fail
202
147
    if os.getuid() != 0:
203
148
        raise Exception("Must run make_jail as root")
204
149
    
205
 
    stagingdir = os.path.join(conf.jail_base, '__staging__')
206
 
    if not os.path.isdir(stagingdir):
207
 
        raise Exception("Staging jail directory does not exist: " +
208
 
            stagingdir)
 
150
    templatedir = os.path.join(conf.jail_base, 'template')
 
151
    if not os.path.isdir(templatedir):
 
152
        raise Exception("Template jail directory does not exist: " +
 
153
            templatedir)
209
154
    # tempdir is for putting backup homes in
210
 
    tempdir = os.path.join(conf.jail_base, '__temp__')
 
155
    tempdir = os.path.join(conf.jail_base, 'temp')
211
156
    if not os.path.exists(tempdir):
212
157
        os.makedirs(tempdir)
213
158
    elif not os.path.isdir(tempdir):
234
179
            # the backup will be un-made.
235
180
            # XXX This will still leave the user's jail in an unusable state,
236
181
            # but at least they won't lose their files.
237
 
            if manifest:
238
 
                (to_add, to_remove) = manifest
239
 
                # Remove redundant files and directories
240
 
                for d in to_remove:
241
 
                    dst = os.path.join(userdir, d)
242
 
                    src = os.path.join(stagingdir, d)
243
 
                    if os.path.isdir(dst):
244
 
                        shutil.rmtree(dst)
245
 
                    elif os.path.isfile(dst):
246
 
                        os.remove(dst)
247
 
                # Add new files
248
 
                for d in to_add:
249
 
                    dst = os.path.join(userdir, d)
250
 
                    src = os.path.join(stagingdir, d)
251
 
                    # Clear the previous file/dir
252
 
                    if os.path.isdir(dst):
253
 
                        shutil.rmtree(dst)
254
 
                    elif os.path.isfile(dst):
255
 
                        os.remove(dst)
256
 
                    # Link the file/dirs
257
 
                    if os.path.isdir(src):
258
 
                        linktree(src, dst)
259
 
                    elif os.path.isfile(src):
260
 
                        os.link(src, dst)
261
 
                    
262
 
            else:
263
 
                # No manifest, do a full rebuild
264
 
                shutil.rmtree(userdir)
265
 
                # Hard-link (copy aliasing) the entire tree over
266
 
                linktree(stagingdir, userdir)
 
182
            shutil.rmtree(userdir)
 
183
 
 
184
            # Hard-link (copy aliasing) the entire tree over
 
185
            linktree(templatedir, userdir)
267
186
        finally:
268
187
            # Set up the user's home directory (restore backup)
269
188
            # First make sure the directory is empty and its parent exists
275
194
            # directory). But it shouldn't fail as homedir should not exist.
276
195
            os.makedirs(homedir)
277
196
            shutil.move(homebackup, homedir)
278
 
        userhomedir = os.path.join(homedir, username)   # Return value
 
197
        return os.path.join(homedir, username)
279
198
    else:
280
199
        # No user jail exists
281
200
        # Hard-link (copy aliasing) the entire tree over
282
 
        linktree(stagingdir, userdir)
 
201
        linktree(templatedir, userdir)
283
202
 
284
203
        # Set up the user's home directory
285
204
        userhomedir = os.path.join(homedir, username)
288
207
        os.chown(userhomedir, uid, uid)
289
208
        # Chmod to rwxr-xr-x (755)
290
209
        os.chmod(userhomedir, 0755)
291
 
 
292
 
    # There is 1 special file which should not be hard-linked, but instead
293
 
    # generated specific to this user: /opt/ivle/lib/conf/conf.py.
294
 
    # "__" username "__" users are exempt (special)
295
 
    if not (username.startswith("__") and username.endswith("__")):
296
 
        make_conf_py(username, userdir, stagingdir, svn_pass)
297
 
 
298
 
    return userhomedir
299
 
 
300
 
def make_conf_py(username, user_jail_dir, staging_dir, svn_pass=None):
301
 
    """
302
 
    Creates (overwriting any existing file) a file /opt/ivle/lib/conf/conf.py
303
 
    in a given user's jail.
304
 
    username: Username.
305
 
    user_jail_dir: User's jail dir, ie. conf.jail_base + username
306
 
    staging_dir: The dir with the staging copy of the jail. (With the
307
 
        template conf.py file).
308
 
    svn_pass: As with make_jail. User's SVN password, but if not supplied,
309
 
        will look up in the DB.
310
 
    """
311
 
    # Note: It is important to delete this file and recreate it (somewhat
312
 
    # ironically beginning by pasting the same contents in again), rather than
313
 
    # simply appending.
314
 
    # Note that all files initially are aliased, so appending would result
315
 
    # in a massive aliasing problem. Deleting and recreating ensures that
316
 
    # the conf.py files are unique to each jail.
317
 
    template_conf_path = os.path.join(staging_dir,"opt/ivle/lib/conf/conf.py")
318
 
    conf_path = os.path.join(user_jail_dir, "opt/ivle/lib/conf/conf.py")
319
 
 
320
 
    # If svn_pass isn't supplied, grab it from the DB
321
 
    if svn_pass is None:
322
 
        dbconn = db.DB()
323
 
        svn_pass = dbconn.get_user(username).svn_pass
324
 
        dbconn.close()
325
 
 
326
 
    # Read the contents of the template conf file
327
 
    try:
328
 
        template_conf_file = open(template_conf_path, "r")
329
 
        template_conf_data = template_conf_file.read()
330
 
        template_conf_file.close()
331
 
    except:
332
 
        # Couldn't open template conf.py for some reason
333
 
        # Just treat it as empty file
334
 
        template_conf_data = ("# Warning: Problem building config script.\n"
335
 
                              "# Could not find template conf.py file.\n")
336
 
 
337
 
    # Remove the target conf file if it exists
338
 
    try:
339
 
        os.remove(conf_path)
340
 
    except OSError:
341
 
        pass
342
 
    conf_file = open(conf_path, "w")
343
 
    conf_file.write(template_conf_data)
344
 
    conf_file.write("\n# The login name for the owner of the jail\n")
345
 
    conf_file.write("login = %s\n" % repr(username))
346
 
    conf_file.write("\n")
347
 
    conf_file.write("# The subversion-only password for the owner of "
348
 
        "the jail\n")
349
 
    conf_file.write("svn_pass = %s\n" % repr(svn_pass))
350
 
    conf_file.close()
351
 
 
352
 
    # Make this file world-readable
353
 
    # (chmod 644 conf_path)
354
 
    os.chmod(conf_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP
355
 
                        | stat.S_IROTH)
 
210
        return userhomedir
356
211
 
357
212
def linktree(src, dst):
358
213
    """Recursively hard-link a directory tree using os.link().
418
273
        if res != 0 and throw_on_error:
419
274
            raise Exception("Unable to create local-auth for %s" % kwargs['login'])
420
275
 
421
 
    # Make sure the file is owned by the web server
422
 
    if create == "c":
423
 
        chown_to_webserver(conf.svn_auth_local)