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:])) |