~launchpad-pqm/launchpad/devel

10637.3.1 by Guilherme Salgado
Use the default python version instead of a hard-coded version
1
#!/usr/bin/python -S
8452.3.3 by Karl Fogel
* utilities/: Add copyright header block to source files that were
2
#
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
3
# Copyright 2009-2010 Canonical Ltd.  This software is licensed under the
8687.15.3 by Karl Fogel
Shorten the copyright header block to two lines.
4
# GNU Affero General Public License version 3 (see the file LICENSE).
8452.3.3 by Karl Fogel
* utilities/: Add copyright header block to source files that were
5
6488.1.3 by Jonathan Lange
Docstrings ahoy!
6
"""Create a user for testing the local Launchpad.
7
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
8
Usage: make-lp-user <username> [<team1> <team2> ...] [-e email]
6488.1.3 by Jonathan Lange
Docstrings ahoy!
9
10
This script will create a usable Launchpad user in the development database to
11
help you test a locally running copy of Launchpad.
12
13
You can add this user to teams by specifying them on the command-line. For
14
example:
15
13401.2.1 by Steve Kowalik
Remove the bazaar-experts celebrity.
16
  make-lp-user fred vcs-imports
6488.1.3 by Jonathan Lange
Docstrings ahoy!
17
13401.2.1 by Steve Kowalik
Remove the bazaar-experts celebrity.
18
will create a user 'fred' and add them to the 'vcs-imports' team.
6488.1.3 by Jonathan Lange
Docstrings ahoy!
19
20
In addition, this script will look in your ~/.ssh directory for public keys
21
and register them for the created user.
22
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
23
If you pass an email address, the new user will have this email address
24
as well as any GPG keys you have for it.
25
6488.1.3 by Jonathan Lange
Docstrings ahoy!
26
The login details will be printed to stdout.
27
28
Please note that this script is for testing purposes only. Do NOT use it in
29
production environments.
30
"""
31
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
32
import _pythonpath
33
34
import os
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
35
from optparse import OptionParser
36
import re
37
import subprocess
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
38
import sys
39
import transaction
40
10427.4.6 by Jeroen Vermeulen
Final polish. I hope.
41
from storm.store import Store
42
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
43
from zope.component import getUtility
44
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
45
from canonical.launchpad.interfaces.gpghandler import IGPGHandler
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
46
from canonical.launchpad.scripts import execute_zcml_for_scripts
14128.2.1 by Danilo Segan
Add the default timeout function so make_lp_user keeps working.
47
from canonical.lazr.timeout import set_default_timeout_function
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
48
from lp.registry.interfaces.gpg import GPGKeyAlgorithm, IGPGKeySet
11882.2.2 by Jonathan Lange
Clear up a heck of a lot of imports from canonical.launchpad.interfaces.
49
from lp.registry.interfaces.person import IPersonSet
50
from lp.registry.interfaces.ssh import ISSHKeySet
51
from lp.registry.interfaces.teammembership import TeamMembershipStatus
8440.1.1 by Curtis Hovey
Updated all imports or LaunchpadObjectFactory to come from lp.test.factory.
52
from lp.testing.factory import LaunchpadObjectFactory
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
53
54
# Shut up, pyflakes.
55
_pythonpath = _pythonpath
56
57
58
DEFAULT_PASSWORD = 'test'
59
factory = LaunchpadObjectFactory()
60
14128.2.1 by Danilo Segan
Add the default timeout function so make_lp_user keeps working.
61
set_default_timeout_function(lambda: 100)
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
62
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
63
def make_person(username, email):
6488.1.3 by Jonathan Lange
Docstrings ahoy!
64
    """Create and return a person with the given username.
65
66
    The email address for the user will be <username>@example.com. The
67
    password will be the value of `DEFAULT_PASSWORD`.
68
69
    These details will be printed to stdout.
70
    """
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
71
    person = factory.makePerson(
72
        name=username, password=DEFAULT_PASSWORD, email=email)
73
    print "username: %s" % (username,)
74
    print "email:    %s" % (email,)
75
    print "password: %s" % (DEFAULT_PASSWORD,)
76
    return person
77
78
79
def add_person_to_teams(person, team_names):
6488.1.3 by Jonathan Lange
Docstrings ahoy!
80
    """Add `person` to the teams named in `team_names`.
81
82
    `person` is provided as its own review, team membership status is always
83
    `APPROVED`. This function will add users even to restricted teams.
84
85
    A list of teams joined will be printed to stdout.
86
    """
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
87
    person_set = getUtility(IPersonSet)
6488.1.4 by Jonathan Lange
Slightly more error handling.
88
    teams_joined = []
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
89
    for team_name in team_names:
90
        team = person_set.getByName(team_name)
6488.1.4 by Jonathan Lange
Slightly more error handling.
91
        if team is None:
92
            print "ERROR: %s not found." % (team_name,)
93
            continue
94
        if not team.is_team:
95
            print "ERROR: %s is not a team." % (team_name,)
96
            continue
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
97
        team.addMember(
98
            person, person, status=TeamMembershipStatus.APPROVED)
6488.1.4 by Jonathan Lange
Slightly more error handling.
99
        teams_joined.append(team_name)
100
    print "teams:    %s" % ' '.join(teams_joined)
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
101
102
103
def add_ssh_public_keys(person):
6488.1.3 by Jonathan Lange
Docstrings ahoy!
104
    """Look for public keys and register them for `person`.
105
106
    This function looks in ~/.ssh/id_rsa.pub and ~/.ssh/id_dsa.pub for SSH
107
    public keys and registers them as SSH keys for `person`.
108
    """
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
109
    ssh_dir = os.path.expanduser('~/.ssh')
110
    key_set = getUtility(ISSHKeySet)
11332.1.1 by Steve Kowalik
Change how SSH keys are added in utilities/make-lp-user, no longer guess the
111
    for filename in ('id_rsa.pub', 'id_dsa.pub'):
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
112
        try:
11435.8.1 by Ian Booth
Use proper file name when reading SSH keys, print message when none found
113
            public_key_file = open(os.path.join(ssh_dir, filename), 'r')
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
114
            try:
115
                public_key = public_key_file.read()
116
            finally:
117
                public_key_file.close()
118
        except (OSError, IOError):
119
            continue
11332.1.1 by Steve Kowalik
Change how SSH keys are added in utilities/make-lp-user, no longer guess the
120
        key_set.new(person, public_key)
121
        print 'Registered SSH key: %s' % (filename,)
11435.8.1 by Ian Booth
Use proper file name when reading SSH keys, print message when none found
122
        break
123
    else:
14128.2.7 by Danilo Segan
A few lint fixes and reverts for unneeded changes.
124
        print 'No SSH key files found in %s' % ssh_dir
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
125
126
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
127
def parse_fingerprints(gpg_output):
128
    """Find key fingerprints in "gpg --fingerprint <email>" output."""
129
    line_prefix = re.compile('\s*Key fingerprint\s*=\s*')
130
    return [
131
        ''.join(re.sub(line_prefix, '', line).split())
132
        for line in gpg_output.splitlines()
133
        if line_prefix.match(line)
134
        ]
135
136
137
def run_native_gpg(arguments):
138
    """Run GPG using the user's real keyring."""
139
    # Need to override GNUPGHOME or we'll get a dummy GPG in a temp
140
    # directory, which won't find any keys.
141
    env = os.environ.copy()
142
    if 'GNUPGHOME' in env:
143
        del env['GNUPGHOME']
10427.4.8 by Jeroen Vermeulen
Beware of translated gpg, thanks adeuring for spotting that.
144
145
    # Prevent translated gpg output from messing up our parsing.
146
    env['LC_ALL'] = 'C'
147
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
148
    command_line = ['gpg'] + arguments
149
    pipe = subprocess.Popen(
150
        command_line, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
151
    stdout, stderr = pipe.communicate()
152
    if stderr != '':
153
        print stderr
154
    if pipe.returncode != 0:
155
        raise Exception('GPG error during "%s"' % ' '.join(command_line))
156
157
    return stdout
158
159
160
def add_gpg_key(person, fingerprint):
161
    """Add the GPG key with the given fingerprint to `person`."""
162
    run_native_gpg([
163
        '--keyserver', 'keyserver.launchpad.dev',
164
        '--send-key', fingerprint
165
        ])
166
167
    gpghandler = getUtility(IGPGHandler)
168
    key = gpghandler.retrieveKey(fingerprint)
169
170
    gpgkeyset = getUtility(IGPGKeySet)
171
    if gpgkeyset.getByFingerprint(fingerprint) is not None:
172
        # We already have this key.
173
        return
174
175
    algorithm = GPGKeyAlgorithm.items[key.algorithm]
176
    can_encrypt = True
177
    lpkey = gpgkeyset.new(
178
        person.id, key.keyid, fingerprint, key.keysize, algorithm,
179
        active=True, can_encrypt=can_encrypt)
180
    Store.of(person).add(lpkey)
181
182
183
def attach_gpg_keys(email, person):
184
    """Attach the GPG key(s) for `email` to `person`."""
185
    output = run_native_gpg(['--fingerprint', email])
186
187
    fingerprints = parse_fingerprints(output)
188
    if len(fingerprints) == 0:
189
        print "No GPG key fingerprints found!"
190
    for fingerprint in fingerprints:
191
        add_gpg_key(person, fingerprint)
192
193
194
def parse_args(arguments):
195
    """Parse command-line arguments.
196
197
    :return: options object.  Among the options are username (a
198
        string) and optionally teams (a list).
199
    """
200
    parser = OptionParser(description="Create a local Launchpad user.")
201
    parser.add_option(
202
        '-e', '--email', action='store', dest='email', default=None,
203
        help="Email address; set to use real GPG key for this address.")
10427.4.4 by Jeroen Vermeulen
Better options processing.
204
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
205
    options, args = parser.parse_args(arguments)
206
    if len(args) == 0:
207
        print __doc__
10427.4.4 by Jeroen Vermeulen
Better options processing.
208
        sys.exit(2)
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
209
210
    options.username = args[0]
211
    options.teams = args[1:]
212
213
    return options
214
215
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
216
def main(arguments):
6488.1.3 by Jonathan Lange
Docstrings ahoy!
217
    """Run the script."""
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
218
    options = parse_args(arguments)
219
    if options.email is None:
220
    	email = '%s@example.com' % options.username
221
    else:
222
        email = options.email
223
10427.4.4 by Jeroen Vermeulen
Better options processing.
224
    execute_zcml_for_scripts()
225
    transaction.begin()
226
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
227
    person = make_person(options.username, email)
228
    add_person_to_teams(person, options.teams)
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
229
    add_ssh_public_keys(person)
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
230
231
    if options.email is not None:
232
        attach_gpg_keys(options.email, person)
233
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
234
    transaction.commit()
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
235
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
236
    return 0
237
238
239
if __name__ == '__main__':
240
    sys.exit(main(sys.argv[1:]))