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

« back to all changes in this revision

Viewing changes to scripts/usrmgt-server

  • Committer: dcoles
  • Date: 2008-07-18 02:40:58 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:912
Makeuser: Makeuser will now chown all files in a users home directory to the
unixid provided by the database. This means remakeallusers.py can be used to
update everyones unixids after a database change. The makeuser script will also 
no longer generate a random unixid when one is not given on the command line.

Database: Change to database so that a sequence is used by default. The allowed  
range is 1000-29999 (let's start at 5000, because 1000+ is used by adduser.  
Reference: http://www.debian.org/doc/debian-policy/ch-opersys.html)
See SF Bug '[ 2012190 ] Student UID generation'
Migration script will reallocate all users a new unixid from the sequence.

Usermgt-Server: Now no longer generates a random unixid. Rely on the database 
to come up with a new sequence number.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/python
2
2
 
 
3
import os
 
4
import pysvn
 
5
import subprocess
3
6
import sys
 
7
import urllib
 
8
from functools import partial
 
9
import traceback
 
10
import logging
 
11
import errno
4
12
 
 
13
import conf
5
14
import common.db
6
15
import common.chat
7
16
import common.makeuser
 
17
import common.studpath
8
18
 
9
19
# usage:
10
20
#   usrmgt-server <port> <magic>
25
35
#   - Rebuild svn auth file
26
36
#   - Rebuild passwd + push to nodes.
27
37
 
28
 
 
29
38
def create_user(props):
30
39
    """Create the database record for the given user.
31
40
       Expected properties:
32
 
        username    - used as a unix login name and svn repository name.
 
41
        login       - used as a unix login name and svn repository name.
33
42
                      STRING REQUIRED 
34
 
        uid         - the unix uid under which execution will take place
 
43
        unixid      - the unix uid under which execution will take place
35
44
                      on the behalf of the user. Don't use 0! If not specified
36
45
                      or None, one will be allocated from the configured
37
46
                      numeric range.
56
65
       Return Value: the uid associated with the user. INT
57
66
    """
58
67
 
59
 
    # FIXME: the IVLE server must check that an admin is doing this!
60
 
 
61
 
    if 'uid' not in props or props['uid'] is None:
62
 
        raise NotImplementedError, "No algorithm for creating uids yet!"
63
 
        # uid = invent-uid
64
 
        # props['uid'] = uid
65
 
 
66
 
    username = props['username']
67
 
    uid = props['uid']
68
 
    try:
69
 
        password = props['password']
70
 
    except KeyError:
71
 
        password = None
72
 
    try:
73
 
        email = props['email']
74
 
    except KeyError:
75
 
        email = None
76
 
    nick = props['nick']
77
 
    fullname = props['fullname']
78
 
    rolenm = props['rolenm']
79
 
    try:
80
 
        studentid = props['studentid']
81
 
    except KeyError:
82
 
        studentid = None
83
 
    common.makeuser.make_user_db(username, uid, password, email, nick,
84
 
                                 fullname, rolenm, studentid)
85
 
 
86
 
    return uid
 
68
    common.makeuser.make_user_db(**props)
 
69
    user = common.db.get_user(props["login"])
 
70
    return user["unixid"]
 
71
 
 
72
def update_user(props):
 
73
    """Create the database record for the given user.
 
74
       Expected properties:
 
75
        login       - user who is making the change (not necessarily the one
 
76
                      being updated).
 
77
        update      - dict of fields to be updated. The fields are all those
 
78
                      in the login table of the db.
 
79
                      'login' required.
 
80
                      Omitted fields will not be set.
 
81
    """
 
82
    update = props['update']
 
83
    # Note: "login" is special - it is not part of the kwargs to
 
84
    # db.update_user, but the first arg - used to find the user to update.
 
85
    # However it doesn't need any special treatment here.
 
86
 
 
87
    db = common.db.DB()
 
88
    db.update_user(**update)
 
89
    db.close()
 
90
 
 
91
def get_login(login, passwd, realm, existing_login, _may_save):
 
92
    """Callback function used by pysvn for authentication.
 
93
    login, passwd: Credentials of the user attempting to log in.
 
94
        passwd in clear (this should be the user's svn_pass, a
 
95
        randomly-generated permanent password for this user, not their main
 
96
        IVLE password).
 
97
    realm, existing_login, _may_save: The 3 arguments passed by pysvn to
 
98
        callback_get_login.
 
99
        The following has been determined empirically, not from docs:
 
100
        existing_login will be the name of the user who owns the process on
 
101
        the first attempt, "" on subsequent attempts. We use this fact.
 
102
    """
 
103
    logging.debug("Getting password for %s (realm %s)" % (login, realm))
 
104
    # Only provide credentials on the _first_ attempt.
 
105
    # If we're being asked again, then it means the credentials failed for
 
106
    # some reason and we should just fail. (This is not desirable, but it's
 
107
    # better than being asked an infinite number of times).
 
108
    if existing_login == "":
 
109
        logging.warning("Could not authenticate SVN for %s" % login)
 
110
        return (False, login, passwd, False)
 
111
    else:
 
112
        return (True, login, passwd, False)
87
113
 
88
114
def activate_user(props):
89
115
    """Create the on-disk stuff for the given user.
94
120
       Return Value: None
95
121
    """
96
122
 
 
123
    os.umask(0022) # Bad, but start_server sets it worse.
 
124
 
97
125
    login = props['login']
98
126
 
99
127
    db = common.db.DB()
104
132
 
105
133
        details = db.get_user(login)
106
134
 
107
 
        # FIXME: make svn config/auth
108
 
 
109
 
        # FIXME: etc, etc.
110
 
 
111
 
        common.makeuser.make_jail(login, details['unixid'])
112
 
 
 
135
        # make svn config/auth
 
136
 
 
137
        logging.debug("Creating repo")
 
138
        common.makeuser.make_svn_repo(login, throw_on_error=False)
 
139
        logging.debug("Creating svn config")
 
140
        common.makeuser.make_svn_config(login, throw_on_error=False)
 
141
        logging.debug("Creating svn auth")
 
142
        passwd = common.makeuser.make_svn_auth(login, throw_on_error=False)
 
143
        logging.debug("passwd: %s" % passwd)
 
144
 
 
145
        svn = pysvn.Client()
 
146
        svn.callback_get_login = partial(get_login, login, passwd)
 
147
 
 
148
        if conf.svn_addr[-1] != '/':
 
149
            conf.svn_addr = conf.svn_addr + "/"
 
150
    
 
151
        # FIXME: This should be a loop over enrolements.
 
152
        #        We're not going to fix this now because it requires
 
153
        #        a large amount of admin console work to manage subject
 
154
        #        offerings.
 
155
        #        Instead, we're just going to use a single offering with
 
156
        #        a "short" name of "info1".
 
157
        logging.debug("Creating /info1")
 
158
        try:
 
159
            svn.mkdir(conf.svn_addr + login + "/info1",
 
160
                      "Initial creation of work directory for Informatics 1")
 
161
        except Exception, exc:
 
162
            logging.warning("While mkdiring info1: %s" % str(exc))
 
163
            pass
 
164
        logging.debug("Creating /stuff")
 
165
        try:
 
166
            svn.mkdir(conf.svn_addr + login + "/stuff",
 
167
                      "Initial creation of directory for miscellania")
 
168
        except Exception, exc:
 
169
            logging.warning("While mkdiring stuff: %s" % str(exc))
 
170
            pass
 
171
 
 
172
        logging.debug("Creating jail")
 
173
        common.makeuser.make_jail(login, details.unixid, svn_pass=passwd)
 
174
 
 
175
        common.makeuser.mount_jail(login)
 
176
 
 
177
        do_checkout(props, svn_pass=passwd)
 
178
 
 
179
        # FIXME: should this be nicer?
 
180
        os.system("chown -R %d:%d %s" \
 
181
                % (details.unixid, details.unixid,
 
182
                   common.studpath.url_to_local(login)[1]))
 
183
 
 
184
        logging.info("Enabling user")
113
185
        db.update_user(login, state='enabled')
114
186
 
115
187
        return {"response": "okay"}
117
189
    finally:
118
190
        db.close()
119
191
 
 
192
def do_checkout(props, svn_pass=None):
 
193
    """Create the default contents of a user's jail by checking out from the
 
194
    repositories.
 
195
    If any directory already exists, just fail silently (so this is not a
 
196
    "wipe-and-checkout", merely a checkout if it failed or something).
 
197
       Expected properties:
 
198
        login       - the user name for the jail
 
199
                      STRING REQUIRED
 
200
       Return Value: None
 
201
    """
 
202
    login = props['login']
 
203
 
 
204
    db = common.db.DB()
 
205
    user = db.get_user(login)
 
206
    # If svn_pass isn't supplied, grab it from the DB
 
207
    if svn_pass is None:
 
208
        svn_pass = user.svn_pass
 
209
    db.close()
 
210
 
 
211
    svn = pysvn.Client()
 
212
    svn.callback_get_login = partial(get_login, login, svn_pass)
 
213
 
 
214
    if conf.svn_addr[-1] != os.sep:
 
215
        conf.svn_addr += os.sep
 
216
 
 
217
    # FIXME: <hack>
 
218
 
 
219
    logging.debug("Checking out directories in the jail")
 
220
    try:
 
221
        svn.checkout(conf.svn_addr + login + "/stuff",
 
222
                     common.studpath.url_to_local(login + "/stuff")[1])
 
223
        os.system("chown -R %d:%d %s" \
 
224
                % (user.unixid, user.unixid,
 
225
                   common.studpath.url_to_local(login + "/stuff")[1]))
 
226
    except Exception, exc:
 
227
        logging.warning("While mkdiring stuff: %s" % str(exc))
 
228
        pass
 
229
    try:
 
230
        svn.checkout(conf.svn_addr + login + "/info1",
 
231
                     common.studpath.url_to_local(login + "/info1")[1])
 
232
        os.system("chown -R %d:%d %s" \
 
233
                % (user.unixid, user.unixid,
 
234
                   common.studpath.url_to_local(login + "/info1")[1]))
 
235
    except Exception, exc:
 
236
        logging.warning("While mkdiring info1: %s" % str(exc))
 
237
        pass
 
238
 
 
239
    # FIXME: </hack>
 
240
 
 
241
    return {"response": "okay"}
 
242
 
120
243
actions = {
121
244
        'create_user':create_user,
122
 
        'activate_user':activate_user
 
245
        'update_user':update_user,
 
246
        'activate_user':activate_user,
 
247
        'do_checkout':do_checkout,
123
248
    }
124
249
 
 
250
def initializer():
 
251
    try:
 
252
        pidfile = open('/var/run/usrmgt-server.pid', 'w')
 
253
        pidfile.write('%d\n' % os.getpid())
 
254
        pidfile.close()
 
255
    except IOError, (errno, strerror):
 
256
        print "Couldn't write PID file. IO error(%s): %s" % (errno, strerror)
 
257
        sys.exit(1)
 
258
 
125
259
def dispatch(props):
 
260
    logging.debug(repr(props))
126
261
    action = props.keys()[0]
127
262
    return actions[action](props[action])
128
263
 
129
264
if __name__ == "__main__":
 
265
    if len(sys.argv) <3:
 
266
        print >>sys.stderr, "Usage: usrmgt-server <port> <magic>"
 
267
        sys.exit(1)
130
268
    port = int(sys.argv[1])
131
269
    magic = sys.argv[2]
132
270
 
133
 
    common.chat.start_server(port, magic, False, dispatch)
 
271
    pid = os.getpid()
 
272
 
 
273
    logging.basicConfig(filename="/var/log/usrmgt.log", level=logging.INFO)
 
274
    logging.info("Starting usrmgt server on port %d (pid = %d)" % (port, pid))
 
275
 
 
276
    common.chat.start_server(port, magic, True, dispatch, initializer)