~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
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
47
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.
48
from lp.registry.interfaces.person import IPersonSet
49
from lp.registry.interfaces.ssh import ISSHKeySet
50
from lp.registry.interfaces.teammembership import TeamMembershipStatus
8440.1.1 by Curtis Hovey
Updated all imports or LaunchpadObjectFactory to come from lp.test.factory.
51
from lp.testing.factory import LaunchpadObjectFactory
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
52
53
# Shut up, pyflakes.
54
_pythonpath = _pythonpath
55
56
57
DEFAULT_PASSWORD = 'test'
58
factory = LaunchpadObjectFactory()
59
60
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
61
def make_person(username, email):
6488.1.3 by Jonathan Lange
Docstrings ahoy!
62
    """Create and return a person with the given username.
63
64
    The email address for the user will be <username>@example.com. The
65
    password will be the value of `DEFAULT_PASSWORD`.
66
67
    These details will be printed to stdout.
68
    """
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
69
    person = factory.makePerson(
70
        name=username, password=DEFAULT_PASSWORD, email=email)
71
    print "username: %s" % (username,)
72
    print "email:    %s" % (email,)
73
    print "password: %s" % (DEFAULT_PASSWORD,)
74
    return person
75
76
77
def add_person_to_teams(person, team_names):
6488.1.3 by Jonathan Lange
Docstrings ahoy!
78
    """Add `person` to the teams named in `team_names`.
79
80
    `person` is provided as its own review, team membership status is always
81
    `APPROVED`. This function will add users even to restricted teams.
82
83
    A list of teams joined will be printed to stdout.
84
    """
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
85
    person_set = getUtility(IPersonSet)
6488.1.4 by Jonathan Lange
Slightly more error handling.
86
    teams_joined = []
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
87
    for team_name in team_names:
88
        team = person_set.getByName(team_name)
6488.1.4 by Jonathan Lange
Slightly more error handling.
89
        if team is None:
90
            print "ERROR: %s not found." % (team_name,)
91
            continue
92
        if not team.is_team:
93
            print "ERROR: %s is not a team." % (team_name,)
94
            continue
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
95
        team.addMember(
96
            person, person, status=TeamMembershipStatus.APPROVED)
6488.1.4 by Jonathan Lange
Slightly more error handling.
97
        teams_joined.append(team_name)
98
    print "teams:    %s" % ' '.join(teams_joined)
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
99
100
101
def add_ssh_public_keys(person):
6488.1.3 by Jonathan Lange
Docstrings ahoy!
102
    """Look for public keys and register them for `person`.
103
104
    This function looks in ~/.ssh/id_rsa.pub and ~/.ssh/id_dsa.pub for SSH
105
    public keys and registers them as SSH keys for `person`.
106
    """
6488.1.1 by Jonathan Lange
Initial commit of utility to make a user on development environment.
107
    ssh_dir = os.path.expanduser('~/.ssh')
108
    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
109
    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.
110
        try:
11435.8.1 by Ian Booth
Use proper file name when reading SSH keys, print message when none found
111
            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.
112
            try:
113
                public_key = public_key_file.read()
114
            finally:
115
                public_key_file.close()
116
        except (OSError, IOError):
117
            continue
11332.1.1 by Steve Kowalik
Change how SSH keys are added in utilities/make-lp-user, no longer guess the
118
        key_set.new(person, public_key)
119
        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
120
        break
121
    else:
122
        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.
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:]))