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 /submissions")
156
svn.mkdir(conf.svn_addr + login + "/submissions",
157
"Initial creation of submissions directory")
158
except Exception, exc:
159
logging.warning("While mkdiring submissions: %s" % str(exc))
161
logging.debug("Creating /stuff")
163
svn.mkdir(conf.svn_addr + login + "/stuff",
164
"Initial creation of directory for miscellania")
165
except Exception, exc:
166
logging.warning("While mkdiring stuff: %s" % str(exc))
169
logging.debug("Creating jail")
170
common.makeuser.make_jail(login, details.unixid)
174
tcf_path = os.path.join(conf.jail_base, 'template/opt/ivle/lib/conf/conf.py')
175
cf_path = os.path.join(conf.jail_base, login, 'opt/ivle/lib/conf/conf.py')
178
cf = open(cf_path, "w")
179
cf.write(open(tcf_path, "r").read())
180
cf.write("# The login name for the owner of the jail\n")
181
cf.write("login = %s\n" % repr(login))
183
cf.write("# The subversion-only password for the owner of the jail\n")
184
cf.write("svn_pass = %s\n" % repr(passwd))
189
logging.debug("Checking out directories in the jail")
191
svn.checkout(conf.svn_addr + login + "/stuff",
192
common.studpath.url_to_local(login + "/stuff")[1])
193
except Exception, exc:
194
logging.warning("While mkdiring stuff: %s" % str(exc))
197
svn.checkout(conf.svn_addr + login + "/submissions",
198
common.studpath.url_to_local(login + "/submissions")[1])
199
except Exception, exc:
200
logging.warning("While mkdiring submissions: %s" % str(exc))
203
svn.checkout(conf.svn_addr + login + "/info1",
204
common.studpath.url_to_local(login + "/info1")[1])
205
except Exception, exc:
206
logging.warning("While mkdiring info1: %s" % str(exc))
209
# FIXME: should this be nicer?
210
os.system("chown -R %d:%d %s" \
211
% (details.unixid, details.unixid,
212
common.studpath.url_to_local(login)[1]))
215
logging.info("Enabling user")
216
db.update_user(login, state='enabled')
218
return {"response": "okay"}
224
'create_user':create_user,
225
'update_user':update_user,
226
'activate_user':activate_user,
230
logging.debug(repr(props))
231
action = props.keys()[0]
232
return actions[action](props[action])
234
if __name__ == "__main__":
236
print >>sys.stderr, "Usage: usrmgt-server <port> <magic>"
238
port = int(sys.argv[1])
243
logging.basicConfig(filename="/var/log/usrmgt.log", level=logging.INFO)
244
logging.info("Starting usrmgt server on port %d (pid = %d)" % (port, pid))
246
common.chat.start_server(port, magic, True, dispatch)