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