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

« back to all changes in this revision

Viewing changes to scripts/usrmgt-server

  • Committer: mattgiuca
  • Date: 2008-06-16 06:44:28 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:774
scripts/diffservice, diff.css: HTML refactor (simpler layout - it's not valid
    to put pre inside a dt).
    Renamed CSS classes to have hyphens instead of underscores (underscores
    are illegal).

Show diffs side-by-side

added added

removed removed

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