34
28
# - Rebuild svn auth file
35
29
# - 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
31
def activate_user(props):
107
32
"""Create the on-disk stuff for the given user.
108
33
Sets the state of the user in the db from pending to enabled.
125
52
# 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")
54
repopath = os.path.join(conf.svn_repo_path, 'users', login)
55
logging.debug("Creating user's Subversion repository")
56
common.makeuser.make_svn_repo(repopath, throw_on_error=False)
58
rebuild_svn_config(props)
60
logging.debug("Adding Subversion authentication")
132
61
passwd = common.makeuser.make_svn_auth(login, throw_on_error=False)
133
62
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
64
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]))
65
common.makeuser.make_jail(login, details.unixid, svn_pass=passwd)
215
67
logging.info("Enabling user")
216
68
db.update_user(login, state='enabled')
75
def rebuild_svn_config(props):
76
"""Rebuilds the svn config file
78
response (okay, failure)
81
common.makeuser.rebuild_svn_config()
83
logging.warning('Rebuild of Subversion authorization config failed!')
84
return{'response': 'failure', 'msg': repr(e)}
86
return {'response': 'okay'}
88
def rebuild_svn_group_config(props):
89
"""Rebuilds the svn group config file
91
response (okay, failure)
94
common.makeuser.rebuild_svn_group_config()
97
'Rebuild of Subversion group authorization config failed!')
98
return{'response': 'failure', 'msg': repr(e)}
100
return {'response': 'okay'}
102
def create_group_repository(props):
103
"""Creates on disk repository for the given group
105
subj_short_name, year, semester, groupnm
107
response (okay, failure)
110
subj_short_name = props['subj_short_name']
112
semester = props['semester']
113
groupnm = props['groupnm']
115
namespace = "_".join([subj_short_name, year, semester, groupnm])
116
repopath = os.path.join(conf.svn_repo_path, 'groups', namespace)
117
logging.debug("Creating Subversion repository %s"%repopath)
119
common.makeuser.make_svn_repo(repopath)
121
logging.error("Failed to create Subversion repository %s: %s"%
123
return {'response': 'failure', 'msg': repr(e)}
125
return {'response': 'okay'}
224
'create_user':create_user,
225
'update_user':update_user,
226
128
'activate_user':activate_user,
129
'create_group_repository':create_group_repository,
130
'rebuild_svn_config':rebuild_svn_config,
131
'rebuild_svn_group_config':rebuild_svn_group_config,
136
pidfile = open('/var/run/usrmgt-server.pid', 'w')
137
pidfile.write('%d\n' % os.getpid())
139
except IOError, (errno, strerror):
140
print "Couldn't write PID file. IO error(%s): %s" % (errno, strerror)
229
143
def dispatch(props):
230
144
logging.debug(repr(props))
231
145
action = props.keys()[0]
232
146
return actions[action](props[action])
234
148
if __name__ == "__main__":
236
print >>sys.stderr, "Usage: usrmgt-server <port> <magic>"
238
port = int(sys.argv[1])
241
149
pid = os.getpid()
243
151
logging.basicConfig(filename="/var/log/usrmgt.log", level=logging.INFO)
244
logging.info("Starting usrmgt server on port %d (pid = %d)" % (port, pid))
152
logging.info("Starting usrmgt server on port %d (pid = %d)" %
153
(conf.usrmgt_port, pid))
246
common.chat.start_server(port, magic, True, dispatch)
155
common.chat.start_server(conf.usrmgt_port, conf.usrmgt_magic, True, dispatch, initializer)