8
from functools import partial
15
import common.makeuser
16
import common.studpath
19
# usrmgt-server <port> <magic>
21
# User management operations:
23
# - [Re]Create jail for a user
24
# - Create a svn repository for a user
28
# - Checkout repository as home directory
30
# - Disable a user's account
31
# - Enable a user's account
33
# - Rebuild svn config
34
# - Rebuild svn auth file
35
# - Rebuild passwd + push to nodes.
37
def create_user(props):
38
"""Create the database record for the given user.
40
login - used as a unix login name and svn repository name.
42
unixid - the unix uid under which execution will take place
43
on the behalf of the user. Don't use 0! If not specified
44
or None, one will be allocated from the configured
47
password - the clear-text password for the user. If this property is
48
absent or None, this is an indication that external
49
authentication should be used (i.e. LDAP).
51
email - the user's email address.
53
nick - the display name to use.
55
fullname - The name of the user for results and/or other official
58
rolenm - The user's role. Must be one of "anyone", "student",
59
"tutor", "lecturer", "admin".
61
studentid - If supplied and not None, the student id of the user for
62
results and/or other official purposes.
64
Return Value: the uid associated with the user. INT
67
if 'unixid' not in props or props['unixid'] is None:
68
# For the time being, just choose a random unixid.
69
# This may result in duplicates, but the unixid is essentially
70
# a monitoring/logging convenience only. Oh, and dups could kill
72
props['unixid'] = random.randrange(5000,10000)
73
# raise NotImplementedError, "No algorithm for creating uids yet!"
75
# props['unixid'] = unixid
77
common.makeuser.make_user_db(**props)
79
return int(props['unixid'])
81
def update_user(props):
82
"""Create the database record for the given user.
84
login - user who is making the change (not necessarily the one
86
update - dict of fields to be updated. The fields are all those
87
in the login table of the db.
89
Omitted fields will not be set.
91
update = props['update']
92
# Note: "login" is special - it is not part of the kwargs to
93
# db.update_user, but the first arg - used to find the user to update.
94
# However it doesn't need any special treatment here.
97
db.update_user(**update)
100
def get_login(login, passwd, _realm, _login, _may_save):
101
"""Callback function used by pysvn for authentication.
103
logging.debug("Getting password for %s (realm %s)" % (login, _realm))
104
return (True, login, passwd, False)
106
def activate_user(props):
107
"""Create the on-disk stuff for the given user.
108
Sets the state of the user in the db from pending to enabled.
110
login - the user name for the jail
115
login = props['login']
121
# FIXME: check we're pending
123
details = db.get_user(login)
125
# make svn config/auth
127
logging.debug("Creating repo")
128
common.makeuser.make_svn_repo(login, throw_on_error=False)
129
logging.debug("Creating svn config")
130
common.makeuser.make_svn_config(login, throw_on_error=False)
131
logging.debug("Creating svn auth")
132
passwd = common.makeuser.make_svn_auth(login, throw_on_error=False)
133
logging.debug("passwd: %s" % passwd)
136
svn.callback_get_login = partial(get_login, login, passwd)
138
if conf.svn_addr[-1] != '/':
139
conf.svn_addr = conf.svn_addr + "/"
141
# FIXME: This should be a loop over enrolements.
142
# We're not going to fix this now because it requires
143
# a large amount of admin console work to manage subject
145
# Instead, we're just going to use a single offering with
146
# a "short" name of "info1".
147
logging.debug("Creating /info1")
149
svn.mkdir(conf.svn_addr + login + "/info1",
150
"Initial creation of work directory for Informatics 1")
151
except Exception, exc:
152
logging.warning("While mkdiring info1: %s" % str(exc))
154
logging.debug("Creating /stuff")
156
svn.mkdir(conf.svn_addr + login + "/stuff",
157
"Initial creation of directory for miscellania")
158
except Exception, exc:
159
logging.warning("While mkdiring stuff: %s" % str(exc))
162
logging.debug("Creating jail")
163
common.makeuser.make_jail(login, details.unixid)
167
tcf_path = os.path.join(conf.jail_base, 'template/opt/ivle/lib/conf/conf.py')
168
cf_path = os.path.join(conf.jail_base, login, 'opt/ivle/lib/conf/conf.py')
171
cf = open(cf_path, "w")
172
cf.write(open(tcf_path, "r").read())
173
cf.write("# The login name for the owner of the jail\n")
174
cf.write("login = %s\n" % repr(login))
176
cf.write("# The subversion-only password for the owner of the jail\n")
177
cf.write("svn_pass = %s\n" % repr(passwd))
180
# Check out the repositories into the student's home dir
181
# FIXME: Call do_checkout instead of replicating this code.
182
# (do_checkout currently doesn't work)
187
logging.debug("Checking out directories in the jail")
189
svn.checkout(conf.svn_addr + login + "/stuff",
190
common.studpath.url_to_local(login + "/stuff")[1])
191
os.system("chown -R %d:%d %s" \
192
% (details.unixid, details.unixid,
193
common.studpath.url_to_local(login + "/stuff")[1]))
194
except Exception, exc:
195
logging.warning("While mkdiring stuff: %s" % str(exc))
198
svn.checkout(conf.svn_addr + login + "/info1",
199
common.studpath.url_to_local(login + "/info1")[1])
200
os.system("chown -R %d:%d %s" \
201
% (details.unixid, details.unixid,
202
common.studpath.url_to_local(login + "/info1")[1]))
203
except Exception, exc:
204
logging.warning("While mkdiring info1: %s" % str(exc))
207
# FIXME: should this be nicer?
208
os.system("chown -R %d:%d %s" \
209
% (details.unixid, details.unixid,
210
common.studpath.url_to_local(login)[1]))
213
logging.info("Enabling user")
214
db.update_user(login, state='enabled')
216
return {"response": "okay"}
221
def do_checkout(props):
222
"""Create the default contents of a user's jail by checking out from the
224
If any directory already exists, just fail silently (so this is not a
225
"wipe-and-checkout", merely a checkout if it failed or something).
227
login - the user name for the jail
231
# XXX / FIXME: This doesn't work - cannot get passwd
232
# (activate_me creates passwd, other svn stuff gets it from jailconf - we
233
# can't access either at this point).
235
login = props['login']
237
svn.callback_get_login = partial(get_login, login, passwd)
239
if conf.svn_addr[-1] != '/':
240
conf.svn_addr = conf.svn_addr + "/"
244
logging.debug("Checking out directories in the jail")
246
svn.checkout(conf.svn_addr + login + "/stuff",
247
common.studpath.url_to_local(login + "/stuff")[1])
248
os.system("chown -R %d:%d %s" \
249
% (details.unixid, details.unixid,
250
common.studpath.url_to_local(login + "/stuff")[1]))
251
except Exception, exc:
252
logging.warning("While mkdiring stuff: %s" % str(exc))
255
svn.checkout(conf.svn_addr + login + "/info1",
256
common.studpath.url_to_local(login + "/info1")[1])
257
os.system("chown -R %d:%d %s" \
258
% (details.unixid, details.unixid,
259
common.studpath.url_to_local(login + "/info1")[1]))
260
except Exception, exc:
261
logging.warning("While mkdiring info1: %s" % str(exc))
264
return {"response": "okay"}
267
'create_user':create_user,
268
'update_user':update_user,
269
'activate_user':activate_user,
270
'do_checkout':do_checkout,
274
logging.debug(repr(props))
275
action = props.keys()[0]
276
return actions[action](props[action])
278
if __name__ == "__main__":
280
print >>sys.stderr, "Usage: usrmgt-server <port> <magic>"
282
port = int(sys.argv[1])
287
logging.basicConfig(filename="/var/log/usrmgt.log", level=logging.INFO)
288
logging.info("Starting usrmgt server on port %d (pid = %d)" % (port, pid))
290
common.chat.start_server(port, magic, True, dispatch)