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
log = logging.FileHandler("/var/log/usrmgt.log")
39
def create_user(props):
40
"""Create the database record for the given user.
42
login - used as a unix login name and svn repository name.
44
unixid - the unix uid under which execution will take place
45
on the behalf of the user. Don't use 0! If not specified
46
or None, one will be allocated from the configured
49
password - the clear-text password for the user. If this property is
50
absent or None, this is an indication that external
51
authentication should be used (i.e. LDAP).
53
email - the user's email address.
55
nick - the display name to use.
57
fullname - The name of the user for results and/or other official
60
rolenm - The user's role. Must be one of "anyone", "student",
61
"tutor", "lecturer", "admin".
63
studentid - If supplied and not None, the student id of the user for
64
results and/or other official purposes.
66
Return Value: the uid associated with the user. INT
69
if 'unixid' not in props or props['unixid'] is None:
70
# For the time being, just choose a random unixid.
71
# This may result in duplicates, but the unixid is essentially
72
# a monitoring/logging convenience only. Oh, and dups could kill
74
props['unixid'] = random.randrange(5000,10000)
75
# raise NotImplementedError, "No algorithm for creating uids yet!"
77
# props['unixid'] = unixid
79
common.makeuser.make_user_db(**props)
81
return int(props['unixid'])
83
def update_user(props):
84
"""Create the database record for the given user.
86
login - user who is making the change (not necessarily the one
88
update - dict of fields to be updated. The fields are all those
89
in the login table of the db.
91
Omitted fields will not be set.
93
update = props['update']
94
# Note: "login" is special - it is not part of the kwargs to
95
# db.update_user, but the first arg - used to find the user to update.
96
# However it doesn't need any special treatment here.
99
db.update_user(**update)
102
def get_login(login, passwd, _realm, _login, _may_save):
103
"""Callback function used by pysvn for authentication.
105
log.debug("Getting password for %s (realm %s)" % (login, _realm))
106
return (True, login, passwd, False)
108
def activate_user(props):
109
"""Create the on-disk stuff for the given user.
110
Sets the state of the user in the db from pending to enabled.
112
login - the user name for the jail
117
login = props['login']
123
# FIXME: check we're pending
125
details = db.get_user(login)
127
# make svn config/auth
129
log.debug("Creating repo")
130
common.makeuser.make_svn_repo(login, throw_on_error=False)
131
log.debug("Creating svn config")
132
common.makeuser.make_svn_config(login, throw_on_error=False)
133
log.debug("Creating svn auth")
134
passwd = common.makeuser.make_svn_auth(login, throw_on_error=False)
135
log.debug("passwd: %s" % passwd)
138
svn.callback_get_login = partial(get_login, login, passwd)
140
if conf.svn_addr[-1] != '/':
141
conf.svn_addr = conf.svn_addr + "/"
143
# FIXME: This should be a loop over enrolements.
144
# We're not going to fix this now because it requires
145
# a large amount of admin console work to manage subject
147
# Instead, we're just going to use a single offering with
148
# a "short" name of "info1".
149
log.debug("Creating /info1")
151
svn.mkdir(conf.svn_addr + login + "/info1",
152
"Initial creation of work directory for Informatics 1")
153
except Exception, exc:
154
log.warning("While mkdiring info1: %s" % str(exc))
156
log.debug("Creating /submissions")
158
svn.mkdir(conf.svn_addr + login + "/submissions",
159
"Initial creation of submissions directory")
160
except Exception, exc:
161
log.warning("While mkdiring submissions: %s" % str(exc))
163
log.debug("Creating /stuff")
165
svn.mkdir(conf.svn_addr + login + "/stuff",
166
"Initial creation of directory for miscellania")
167
except Exception, exc:
168
log.warning("While mkdiring stuff: %s" % str(exc))
171
log.debug("Creating jail")
172
common.makeuser.make_jail(login, details.unixid)
176
tcf_path = os.path.join(conf.jail_base, 'template/opt/ivle/lib/conf/conf.py')
177
cf_path = os.path.join(conf.jail_base, login, 'opt/ivle/lib/conf/conf.py')
180
cf = open(cf_path, "w")
181
cf.write(open(tcf_path, "r").read())
182
cf.write("# The login name for the owner of the jail\n")
183
cf.write("login = %s\n" % repr(login))
185
cf.write("# The subversion-only password for the owner of the jail\n")
186
cf.write("svn_pass = %s\n" % repr(passwd))
191
log.debug("Checking out directories in the jail")
193
svn.checkout(conf.svn_addr + login + "/stuff",
194
common.studpath.url_to_local(login + "/stuff")[1])
195
except Exception, exc:
196
log.warning("While mkdiring stuff: %s" % str(exc))
199
svn.checkout(conf.svn_addr + login + "/submissions",
200
common.studpath.url_to_local(login + "/submissions")[1])
201
except Exception, exc:
202
log.warning("While mkdiring submissions: %s" % str(exc))
205
svn.checkout(conf.svn_addr + login + "/info1",
206
common.studpath.url_to_local(login + "/info1")[1])
207
except Exception, exc:
208
log.warning("While mkdiring info1: %s" % str(exc))
211
# FIXME: should this be nicer?
212
os.system("chown -R %d:%d %s" \
213
% (details.unixid, details.unixid,
214
common.studpath.url_to_local(login)[1]))
217
log.info("Enabling user")
218
db.update_user(login, state='enabled')
220
return {"response": "okay"}
226
'create_user':create_user,
227
'update_user':update_user,
228
'activate_user':activate_user,
232
log.debug(repr(props))
233
action = props.keys()[0]
234
return actions[action](props[action])
236
if __name__ == "__main__":
237
port = int(sys.argv[1])
242
log.info("Starting usrmgt server on port %d (pid = %d)" % (port, pid))
244
common.chat.start_server(port, magic, True, dispatch)