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