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