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