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

« back to all changes in this revision

Viewing changes to scripts/usrmgt-server

  • Committer: mattgiuca
  • Date: 2008-03-07 15:12:02 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:669
Timestamps are now stored within the program as Python "time" module's
    "struct_time" objects, rather than strings directly from the DB.
    They are parsed into struct_time objects when reading from the db.
    They are formatted into SQL Timestamp strings when writing to the db.
    This allows them to be manipulated and compared within the program.

common.db: _escape now accepts struct_time objects - it formats them into SQL
            time strings.
common.user: The User constructor now parses "acct_exp", "pass_exp" and
            "last_login" fields as timestamp strings, and stores them
            internally as struct_time.
tutorialservice: When recording a submission, the "date" field is now stored
            as a struct_time, not a formatted string.
login.py: When logging in, uncommented call to write last_login to the DB,
            passing the current local time. (This now works correctly).
            Note that this is done after retrieving the user details, so the
            value of last_login stored in the session is the _old_ last login,
            not the new one (this is intentional).

(With Tom Conway).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/python
2
2
 
3
3
import os
 
4
import pysvn
 
5
import subprocess
4
6
import sys
 
7
import urllib
 
8
from functools import partial
 
9
import traceback
5
10
import logging
6
11
 
7
12
import conf
20
25
#           - create repository
21
26
#           - svn config
22
27
#           - svn auth
 
28
#       - Checkout repository as home directory
23
29
#       - /etc/passwd entry
24
30
#   - Disable a user's account
25
31
#   - Enable a user's account
28
34
#   - Rebuild svn auth file
29
35
#   - Rebuild passwd + push to nodes.
30
36
 
 
37
def create_user(props):
 
38
    """Create the database record for the given user.
 
39
       Expected properties:
 
40
        login       - used as a unix login name and svn repository name.
 
41
                      STRING REQUIRED 
 
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
 
45
                      numeric range.
 
46
                      INT OPTIONAL
 
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).
 
50
                      STRING OPTIONAL
 
51
        email       - the user's email address.
 
52
                      STRING OPTIONAL
 
53
        nick        - the display name to use.
 
54
                      STRING REQUIRED
 
55
        fullname    - The name of the user for results and/or other official
 
56
                      purposes.
 
57
                      STRING REQUIRED
 
58
        rolenm      - The user's role. Must be one of "anyone", "student",
 
59
                      "tutor", "lecturer", "admin".
 
60
                      STRING/ENUM REQUIRED
 
61
        studentid   - If supplied and not None, the student id of the user for
 
62
                      results and/or other official purposes.
 
63
                      STRING OPTIONAL
 
64
       Return Value: the uid associated with the user. INT
 
65
    """
 
66
 
 
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
 
71
        # each other. <sigh>
 
72
        props['unixid'] = random.randrange(5000,10000)
 
73
        # raise NotImplementedError, "No algorithm for creating uids yet!"
 
74
        # unixid = invent-uid
 
75
        # props['unixid'] = unixid
 
76
 
 
77
    common.makeuser.make_user_db(**props)
 
78
 
 
79
    return int(props['unixid'])
 
80
 
 
81
def update_user(props):
 
82
    """Create the database record for the given user.
 
83
       Expected properties:
 
84
        login       - user who is making the change (not necessarily the one
 
85
                      being updated).
 
86
        update      - dict of fields to be updated. The fields are all those
 
87
                      in the login table of the db.
 
88
                      'login' required.
 
89
                      Omitted fields will not be set.
 
90
    """
 
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.
 
95
 
 
96
    db = common.db.DB()
 
97
    db.update_user(**update)
 
98
    db.close()
 
99
 
 
100
def get_login(login, passwd, _realm, _login, _may_save):
 
101
    """Callback function used by pysvn for authentication.
 
102
    """
 
103
    logging.debug("Getting password for %s (realm %s)" % (login, _realm))
 
104
    return (True, login, passwd, False)
 
105
 
31
106
def activate_user(props):
32
107
    """Create the on-disk stuff for the given user.
33
108
       Sets the state of the user in the db from pending to enabled.
37
112
       Return Value: None
38
113
    """
39
114
 
40
 
    os.umask(0022) # Bad, but start_server sets it worse.
41
 
 
42
115
    login = props['login']
43
116
 
44
117
    db = common.db.DB()
51
124
 
52
125
        # make svn config/auth
53
126
 
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)
57
 
 
58
 
        rebuild_svn_config(props)
59
 
 
60
 
        logging.debug("Adding Subversion authentication")
 
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")
61
132
        passwd = common.makeuser.make_svn_auth(login, throw_on_error=False)
62
133
        logging.debug("passwd: %s" % passwd)
63
134
 
 
135
        svn = pysvn.Client()
 
136
        svn.callback_get_login = partial(get_login, login, passwd)
 
137
 
 
138
        if conf.svn_addr[-1] != '/':
 
139
            conf.svn_addr = conf.svn_addr + "/"
 
140
    
 
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
 
144
        #        offerings.
 
145
        #        Instead, we're just going to use a single offering with
 
146
        #        a "short" name of "info1".
 
147
        logging.debug("Creating /info1")
 
148
        try:
 
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))
 
153
            pass
 
154
        logging.debug("Creating /stuff")
 
155
        try:
 
156
            svn.mkdir(conf.svn_addr + login + "/stuff",
 
157
                      "Initial creation of directory for miscellania")
 
158
        except Exception, exc:
 
159
            logging.warning("While mkdiring stuff: %s" % str(exc))
 
160
            pass
 
161
 
64
162
        logging.debug("Creating jail")
65
 
        common.makeuser.make_jail(login, details.unixid, svn_pass=passwd)
 
163
        common.makeuser.make_jail(login, details.unixid)
 
164
 
 
165
        # FIXME: <hack>
 
166
 
 
167
        tcf_path = os.path.join(conf.jail_base, 'template/opt/ivle/lib/conf/conf.py')
 
168
        cf_path = os.path.join(conf.jail_base, login, 'opt/ivle/lib/conf/conf.py')
 
169
 
 
170
        os.remove(cf_path)
 
171
        cf = open(cf_path, "w")
 
172
        cf.write(open(tcf_path, "r").read())
 
173
        cf.write("# The login name for the owner of the jail\n")
 
174
        cf.write("login = %s\n" % repr(login))
 
175
        cf.write("\n")
 
176
        cf.write("# The subversion-only password for the owner of the jail\n")
 
177
        cf.write("svn_pass = %s\n" % repr(passwd))
 
178
        cf.close()
 
179
 
 
180
        # FIXME: </hack>
 
181
 
 
182
        logging.debug("Checking out directories in the jail")
 
183
        try:
 
184
            svn.checkout(conf.svn_addr + login + "/stuff",
 
185
                         common.studpath.url_to_local(login + "/stuff")[1])
 
186
        except Exception, exc:
 
187
            logging.warning("While mkdiring stuff: %s" % str(exc))
 
188
            pass
 
189
        try:
 
190
            svn.checkout(conf.svn_addr + login + "/info1",
 
191
                         common.studpath.url_to_local(login + "/info1")[1])
 
192
        except Exception, exc:
 
193
            logging.warning("While mkdiring info1: %s" % str(exc))
 
194
            pass
 
195
 
 
196
        # FIXME: should this be nicer?
 
197
        os.system("chown -R %d:%d %s" \
 
198
                % (details.unixid, details.unixid,
 
199
                   common.studpath.url_to_local(login)[1]))
 
200
 
66
201
 
67
202
        logging.info("Enabling user")
68
203
        db.update_user(login, state='enabled')
72
207
    finally:
73
208
        db.close()
74
209
 
75
 
def rebuild_svn_config(props):
76
 
    """Rebuilds the svn config file
77
 
    Return value:
78
 
        response (okay, failure)
79
 
    """
80
 
    try:
81
 
        common.makeuser.rebuild_svn_config()
82
 
    except Exception, e:
83
 
        logging.warning('Rebuild of Subversion authorization config failed!')
84
 
        return{'response': 'failure', 'msg': repr(e)}
85
 
 
86
 
    return {'response': 'okay'}
87
 
 
88
 
def rebuild_svn_group_config(props):
89
 
    """Rebuilds the svn group config file
90
 
    Return value:
91
 
        response (okay, failure)
92
 
    """
93
 
    try:
94
 
        common.makeuser.rebuild_svn_group_config()
95
 
    except Exception, e:
96
 
        logging.warning(
97
 
            'Rebuild of Subversion group authorization config failed!')
98
 
        return{'response': 'failure', 'msg': repr(e)}
99
 
 
100
 
    return {'response': 'okay'}
101
 
 
102
 
def create_group_repository(props):
103
 
    """Creates on disk repository for the given group
104
 
    Expected properties:
105
 
        subj_short_name, year, semester, groupnm
106
 
    Return value:
107
 
        response (okay, failure)
108
 
    """
109
 
 
110
 
    subj_short_name = props['subj_short_name']
111
 
    year = props['year']
112
 
    semester = props['semester']
113
 
    groupnm = props['groupnm']
114
 
 
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)
118
 
    try:
119
 
        common.makeuser.make_svn_repo(repopath)
120
 
    except Exception, e:
121
 
        logging.error("Failed to create Subversion repository %s: %s"%
122
 
            (repopath,repr(e)))
123
 
        return {'response': 'failure', 'msg': repr(e)}
124
 
 
125
 
    return {'response': 'okay'}
126
 
 
127
210
actions = {
 
211
        'create_user':create_user,
 
212
        'update_user':update_user,
128
213
        '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,
132
214
    }
133
215
 
134
 
def initializer():
135
 
    try:
136
 
        pidfile = open('/var/run/usrmgt-server.pid', 'w')
137
 
        pidfile.write('%d\n' % os.getpid())
138
 
        pidfile.close()
139
 
    except IOError, (errno, strerror):
140
 
        print "Couldn't write PID file. IO error(%s): %s" % (errno, strerror)
141
 
        sys.exit(1)
142
 
 
143
216
def dispatch(props):
144
217
    logging.debug(repr(props))
145
218
    action = props.keys()[0]
146
219
    return actions[action](props[action])
147
220
 
148
221
if __name__ == "__main__":
 
222
    if len(sys.argv) <3:
 
223
        print >>sys.stderr, "Usage: usrmgt-server <port> <magic>"
 
224
        sys.exit(1)
 
225
    port = int(sys.argv[1])
 
226
    magic = sys.argv[2]
 
227
 
149
228
    pid = os.getpid()
150
229
 
151
230
    logging.basicConfig(filename="/var/log/usrmgt.log", level=logging.INFO)
152
 
    logging.info("Starting usrmgt server on port %d (pid = %d)" %
153
 
                 (conf.usrmgt_port, pid))
 
231
    logging.info("Starting usrmgt server on port %d (pid = %d)" % (port, pid))
154
232
 
155
 
    common.chat.start_server(conf.usrmgt_port, conf.usrmgt_magic, True, dispatch, initializer)
 
233
    common.chat.start_server(port, magic, True, dispatch)