9389.6.6
by Michael Hudson
move main to its own file, add standard header to all new files |
1 |
# Copyright 2009 Canonical Ltd. This software is licensed under the
|
2 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
|
3 |
||
9389.6.9
by Michael Hudson
docstrings, __all__s and a little whitespace |
4 |
"""Code to actually run the tests in an EC2 instance."""
|
9389.6.6
by Michael Hudson
move main to its own file, add standard header to all new files |
5 |
|
6 |
__metaclass__ = type |
|
9389.6.9
by Michael Hudson
docstrings, __all__s and a little whitespace |
7 |
__all__ = [ |
8 |
'EC2TestRunner', |
|
9 |
'TRUNK_BRANCH', |
|
10 |
]
|
|
9389.6.6
by Michael Hudson
move main to its own file, add standard header to all new files |
11 |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
12 |
import os |
13 |
import pickle |
|
14 |
import re |
|
15 |
import sys |
|
16 |
||
17 |
from bzrlib.branch import Branch |
|
18 |
from bzrlib.bzrdir import BzrDir |
|
19 |
from bzrlib.config import GlobalConfig |
|
20 |
from bzrlib.errors import UncommittedChanges |
|
21 |
from bzrlib.plugins.pqm.pqm_submit import ( |
|
22 |
NoPQMSubmissionAddress, PQMSubmission) |
|
23 |
||
24 |
||
25 |
TRUNK_BRANCH = 'bzr+ssh://bazaar.launchpad.net/~launchpad-pqm/launchpad/devel' |
|
26 |
||
27 |
||
28 |
class UnknownBranchURL(Exception): |
|
29 |
"""Raised when we try to parse an unrecognized branch url."""
|
|
30 |
||
31 |
def __init__(self, branch_url): |
|
32 |
Exception.__init__( |
|
33 |
self, |
|
34 |
"Couldn't parse '%s', not a Launchpad branch." % (branch_url,)) |
|
35 |
||
9636.1.2
by Jonathan Lange
More PEP 8 cleanups |
36 |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
37 |
def parse_branch_url(branch_url): |
38 |
"""Given the URL of a branch, return its components in a dict."""
|
|
39 |
_lp_match = re.compile( |
|
40 |
r'lp:\~([^/]+)/([^/]+)/([^/]+)$').match |
|
41 |
_bazaar_match = re.compile( |
|
42 |
r'bzr+ssh://bazaar.launchpad.net/\~([^/]+)/([^/]+)/([^/]+)$').match |
|
43 |
match = _lp_match(branch_url) |
|
44 |
if match is None: |
|
45 |
match = _bazaar_match(branch_url) |
|
46 |
if match is None: |
|
47 |
raise UnknownBranchURL(branch_url) |
|
48 |
owner = match.group(1) |
|
49 |
product = match.group(2) |
|
50 |
branch = match.group(3) |
|
51 |
unique_name = '~%s/%s/%s' % (owner, product, branch) |
|
52 |
url = 'bzr+ssh://bazaar.launchpad.net/%s' % (unique_name,) |
|
53 |
return dict( |
|
54 |
owner=owner, product=product, branch=branch, unique_name=unique_name, |
|
55 |
url=url) |
|
56 |
||
57 |
||
58 |
def normalize_branch_input(data): |
|
59 |
"""Given 'data' return a ('dest', 'src') pair.
|
|
60 |
||
61 |
:param data: One of::
|
|
62 |
- a double of (sourcecode_location, branch_url).
|
|
63 |
If 'sourcecode_location' is Launchpad, then 'branch_url' can
|
|
64 |
also be the name of a branch of launchpad owned by
|
|
65 |
launchpad-pqm.
|
|
66 |
- a singleton of (branch_url,)
|
|
67 |
- a singleton of (sourcecode_location,) where
|
|
68 |
sourcecode_location corresponds to a Launchpad upstream
|
|
69 |
project as well as a rocketfuel sourcecode location.
|
|
70 |
- a string which could populate any of the above singletons.
|
|
71 |
||
72 |
:return: ('dest', 'src') where 'dest' is the destination
|
|
73 |
sourcecode location in the rocketfuel tree and 'src' is the
|
|
74 |
URL of the branch to put there. The URL can be either a bzr+ssh
|
|
75 |
URL or the name of a branch of launchpad owned by launchpad-pqm.
|
|
76 |
"""
|
|
77 |
# XXX: JonathanLange 2009-06-05: Should convert lp: URL branches to
|
|
78 |
# bzr+ssh:// branches.
|
|
79 |
if isinstance(data, basestring): |
|
80 |
data = (data,) |
|
81 |
if len(data) == 2: |
|
82 |
# Already in dest, src format.
|
|
83 |
return data |
|
84 |
if len(data) != 1: |
|
85 |
raise ValueError( |
|
86 |
'invalid argument for ``branches`` argument: %r' % |
|
87 |
(data,)) |
|
88 |
branch_location = data[0] |
|
89 |
try: |
|
90 |
parsed_url = parse_branch_url(branch_location) |
|
91 |
except UnknownBranchURL: |
|
92 |
return branch_location, 'lp:%s' % (branch_location,) |
|
93 |
return parsed_url['product'], parsed_url['url'] |
|
94 |
||
95 |
||
96 |
def parse_specified_branches(branches): |
|
97 |
"""Given 'branches' from the command line, return a sanitized dict.
|
|
98 |
||
99 |
The dict maps sourcecode locations to branch URLs, according to the
|
|
100 |
rules in `normalize_branch_input`.
|
|
101 |
"""
|
|
102 |
return dict(map(normalize_branch_input, branches)) |
|
103 |
||
104 |
||
105 |
class EC2TestRunner: |
|
106 |
||
107 |
name = 'ec2-test-runner' |
|
108 |
||
9397.1.6
by Michael Hudson
fix typo and remove inanity that made the consequence surprising. |
109 |
message = image = None |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
110 |
_running = False |
111 |
||
112 |
def __init__(self, branch, email=False, file=None, test_options='-vv', |
|
113 |
headless=False, branches=(), |
|
114 |
pqm_message=None, pqm_public_location=None, |
|
9397.2.5
by Michael Hudson
move a bunch of code from somewhere where it doesn't belong to somewhere else |
115 |
pqm_submit_location=None, |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
116 |
open_browser=False, pqm_email=None, |
9636.1.14
by Jonathan Lange
Drop launchpad-login from the vals dictionary. |
117 |
include_download_cache_changes=None, instance=None, |
10287.1.2
by Guilherme Salgado
Refactor the ec2 timeout code to make sure it's not used for 'ec2 land' |
118 |
launchpad_login=None, |
119 |
timeout=None): |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
120 |
"""Create a new EC2TestRunner.
|
121 |
||
10287.1.2
by Guilherme Salgado
Refactor the ec2 timeout code to make sure it's not used for 'ec2 land' |
122 |
:param timeout: Number of minutes before we force a shutdown. This is
|
123 |
useful because sometimes the normal instance termination might
|
|
124 |
fail.
|
|
125 |
||
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
126 |
- original_branch
|
127 |
- test_options
|
|
128 |
- headless
|
|
129 |
- include_download_cache_changes
|
|
130 |
- download_cache_additions
|
|
131 |
- branches (parses, validates)
|
|
132 |
- message (after validating PQM submisson)
|
|
133 |
- email (after validating email capabilities)
|
|
134 |
- image (after connecting to ec2)
|
|
9636.1.14
by Jonathan Lange
Drop launchpad-login from the vals dictionary. |
135 |
- file
|
10287.1.2
by Guilherme Salgado
Refactor the ec2 timeout code to make sure it's not used for 'ec2 land' |
136 |
- timeout
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
137 |
"""
|
9636.1.6
by Jonathan Lange
Remove spurious comment. |
138 |
self.original_branch = branch |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
139 |
self.test_options = test_options |
140 |
self.headless = headless |
|
141 |
self.include_download_cache_changes = include_download_cache_changes |
|
142 |
self.open_browser = open_browser |
|
9636.1.10
by Jonathan Lange
Remove 'branch' from vals, since only the TestRunner uses it. |
143 |
self.file = file |
9636.1.14
by Jonathan Lange
Drop launchpad-login from the vals dictionary. |
144 |
self._launchpad_login = launchpad_login |
10287.1.2
by Guilherme Salgado
Refactor the ec2 timeout code to make sure it's not used for 'ec2 land' |
145 |
self.timeout = timeout |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
146 |
|
147 |
trunk_specified = False |
|
148 |
trunk_branch = TRUNK_BRANCH |
|
149 |
||
150 |
# normalize and validate branches
|
|
151 |
branches = parse_specified_branches(branches) |
|
152 |
try: |
|
153 |
launchpad_url = branches.pop('launchpad') |
|
154 |
except KeyError: |
|
155 |
# No Launchpad branch specified.
|
|
156 |
pass
|
|
157 |
else: |
|
158 |
try: |
|
159 |
parsed_url = parse_branch_url(launchpad_url) |
|
160 |
except UnknownBranchURL: |
|
161 |
user = 'launchpad-pqm' |
|
162 |
src = ('bzr+ssh://bazaar.launchpad.net/' |
|
163 |
'~launchpad-pqm/launchpad/%s' % (launchpad_url,)) |
|
164 |
else: |
|
165 |
user = parsed_url['owner'] |
|
166 |
src = parsed_url['url'] |
|
167 |
if user == 'launchpad-pqm': |
|
168 |
trunk_specified = True |
|
169 |
trunk_branch = src |
|
9636.1.10
by Jonathan Lange
Remove 'branch' from vals, since only the TestRunner uses it. |
170 |
self._trunk_branch = trunk_branch |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
171 |
self.branches = branches.items() |
172 |
||
173 |
# XXX: JonathanLange 2009-05-31: The trunk_specified stuff above and
|
|
174 |
# the pqm location stuff below are actually doing the equivalent of
|
|
175 |
# preparing a merge directive. Perhaps we can leverage that to make
|
|
176 |
# this code simpler.
|
|
177 |
self.download_cache_additions = None |
|
178 |
if branch is None: |
|
179 |
config = GlobalConfig() |
|
180 |
if pqm_message is not None: |
|
181 |
raise ValueError('Cannot submit trunk to pqm.') |
|
182 |
else: |
|
183 |
(tree, |
|
184 |
bzrbranch, |
|
185 |
relpath) = BzrDir.open_containing_tree_or_branch(branch) |
|
10542.2.3
by Jelmer Vernooij
Use branch-specific configuration if possible, to allow overriding the SMTP server and from address for a few branches. |
186 |
config = bzrbranch.get_config() |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
187 |
|
188 |
if pqm_message is not None or tree is not None: |
|
189 |
# if we are going to maybe send a pqm_message, we're going to
|
|
190 |
# go down this path. Also, even if we are not but this is a
|
|
191 |
# local branch, we're going to use the PQM machinery to make
|
|
192 |
# sure that the local branch has been made public, and has all
|
|
193 |
# working changes there.
|
|
194 |
if tree is None: |
|
195 |
# remote. We will make some assumptions.
|
|
196 |
if pqm_public_location is None: |
|
197 |
pqm_public_location = branch |
|
198 |
if pqm_submit_location is None: |
|
199 |
pqm_submit_location = trunk_branch |
|
200 |
elif pqm_submit_location is None and trunk_specified: |
|
201 |
pqm_submit_location = trunk_branch |
|
202 |
# modified from pqm_submit.py
|
|
203 |
submission = PQMSubmission( |
|
204 |
source_branch=bzrbranch, |
|
205 |
public_location=pqm_public_location, |
|
206 |
message=pqm_message or '', |
|
207 |
submit_location=pqm_submit_location, |
|
208 |
tree=tree) |
|
209 |
if tree is not None: |
|
210 |
# this is the part we want to do whether or not we're
|
|
211 |
# submitting.
|
|
9397.1.11
by Michael Hudson
never meant to commit this bit |
212 |
submission.check_tree() # any working changes |
213 |
submission.check_public_branch() # everything public |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
214 |
branch = submission.public_location |
215 |
if (include_download_cache_changes is None or |
|
216 |
include_download_cache_changes): |
|
217 |
# We need to get the download cache settings
|
|
218 |
cache_tree, cache_bzrbranch, cache_relpath = ( |
|
219 |
BzrDir.open_containing_tree_or_branch( |
|
220 |
os.path.join( |
|
221 |
self.original_branch, 'download-cache'))) |
|
222 |
cache_tree.lock_read() |
|
223 |
try: |
|
224 |
cache_basis_tree = cache_tree.basis_tree() |
|
225 |
cache_basis_tree.lock_read() |
|
226 |
try: |
|
227 |
delta = cache_tree.changes_from( |
|
228 |
cache_basis_tree, want_unversioned=True) |
|
229 |
unversioned = [ |
|
230 |
un for un in delta.unversioned |
|
231 |
if not cache_tree.is_ignored(un[0])] |
|
232 |
added = delta.added |
|
233 |
self.download_cache_additions = ( |
|
234 |
unversioned + added) |
|
235 |
finally: |
|
236 |
cache_basis_tree.unlock() |
|
237 |
finally: |
|
238 |
cache_tree.unlock() |
|
239 |
if pqm_message is not None: |
|
240 |
if self.download_cache_additions: |
|
241 |
raise UncommittedChanges(cache_tree) |
|
242 |
# get the submission message
|
|
243 |
mail_from = config.get_user_option('pqm_user_email') |
|
244 |
if not mail_from: |
|
245 |
mail_from = config.username() |
|
246 |
# Make sure this isn't unicode
|
|
247 |
mail_from = mail_from.encode('utf8') |
|
248 |
if pqm_email is None: |
|
249 |
if tree is None: |
|
250 |
pqm_email = ( |
|
251 |
"Launchpad PQM <launchpad@pqm.canonical.com>") |
|
252 |
else: |
|
253 |
pqm_email = config.get_user_option('pqm_email') |
|
254 |
if not pqm_email: |
|
255 |
raise NoPQMSubmissionAddress(bzrbranch) |
|
256 |
mail_to = pqm_email.encode('utf8') # same here |
|
257 |
self.message = submission.to_email(mail_from, mail_to) |
|
258 |
elif (self.download_cache_additions and |
|
259 |
self.include_download_cache_changes is None): |
|
260 |
raise UncommittedChanges( |
|
261 |
cache_tree, |
|
262 |
'You must select whether to include download cache '
|
|
263 |
'changes (see --include-download-cache-changes and '
|
|
264 |
'--ignore-download-cache-changes, -c and -g '
|
|
265 |
'respectively), or '
|
|
266 |
'commit or remove the files in the download-cache.') |
|
9636.1.10
by Jonathan Lange
Remove 'branch' from vals, since only the TestRunner uses it. |
267 |
self._branch = branch |
268 |
||
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
269 |
if email is not False: |
270 |
if email is True: |
|
271 |
email = [config.username()] |
|
272 |
if not email[0]: |
|
273 |
raise ValueError('cannot find your email address.') |
|
274 |
elif isinstance(email, basestring): |
|
275 |
email = [email] |
|
276 |
else: |
|
277 |
tmp = [] |
|
278 |
for item in email: |
|
279 |
if not isinstance(item, basestring): |
|
280 |
raise ValueError( |
|
9636.1.2
by Jonathan Lange
More PEP 8 cleanups |
281 |
'email must be True, False, a string, or a list '
|
282 |
'of strings') |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
283 |
tmp.append(item) |
284 |
email = tmp |
|
285 |
else: |
|
286 |
email = None |
|
287 |
self.email = email |
|
288 |
||
289 |
# Email configuration.
|
|
290 |
if email is not None or pqm_message is not None: |
|
9636.1.11
by Jonathan Lange
The SMTP config doesn't need to be in vals. |
291 |
self._smtp_server = config.get_user_option('smtp_server') |
292 |
if self._smtp_server is None or self._smtp_server == 'localhost': |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
293 |
raise ValueError( |
294 |
'To send email, a remotely accessible smtp_server (and '
|
|
295 |
'smtp_username and smtp_password, if necessary) must be '
|
|
296 |
'configured in bzr. See the SMTP server information '
|
|
297 |
'here: https://wiki.canonical.com/EmailSetup .') |
|
9636.1.11
by Jonathan Lange
The SMTP config doesn't need to be in vals. |
298 |
self._smtp_username = config.get_user_option('smtp_username') |
299 |
self._smtp_password = config.get_user_option('smtp_password') |
|
10542.2.1
by Jelmer Vernooij
Use configured email address in Bazaar as From address. |
300 |
self._from_email = config.username() |
301 |
if not self._from_email: |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
302 |
raise ValueError( |
303 |
'To send email, your bzr email address must be set '
|
|
304 |
'(use ``bzr whoami``).') |
|
305 |
||
9397.2.5
by Michael Hudson
move a bunch of code from somewhere where it doesn't belong to somewhere else |
306 |
self._instance = instance |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
307 |
|
308 |
def log(self, msg): |
|
309 |
"""Log a message on stdout, flushing afterwards."""
|
|
310 |
# XXX: JonathanLange 2009-05-31 bug=383076: This should use Python
|
|
311 |
# logging, rather than printing to stdout.
|
|
312 |
sys.stdout.write(msg) |
|
313 |
sys.stdout.flush() |
|
314 |
||
315 |
def configure_system(self): |
|
9550.13.2
by Michael Hudson
move towards using a pre-setup account |
316 |
user_connection = self._instance.connect() |
10287.1.2
by Guilherme Salgado
Refactor the ec2 timeout code to make sure it's not used for 'ec2 land' |
317 |
if self.timeout is not None: |
318 |
user_connection.perform( |
|
319 |
"echo sudo shutdown -h now | at today + %d minutes" |
|
320 |
% self.timeout) |
|
9397.1.14
by Michael Hudson
user_p -> as_user, root_p -> as_root |
321 |
as_user = user_connection.perform |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
322 |
# Set up bazaar.conf with smtp information if necessary
|
323 |
if self.email or self.message: |
|
10271.3.3
by Michael Hudson
another fix... |
324 |
as_user('[ -d .bazaar ] || mkdir .bazaar') |
9550.13.34
by Michael Hudson
make using sftp more convenient |
325 |
bazaar_conf_file = user_connection.sftp.open( |
9550.13.40
by Michael Hudson
self-review-ish comments |
326 |
".bazaar/bazaar.conf", 'w') |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
327 |
bazaar_conf_file.write( |
10542.2.1
by Jelmer Vernooij
Use configured email address in Bazaar as From address. |
328 |
'email = %s\n' % (self._from_email,)) |
329 |
bazaar_conf_file.write( |
|
9636.1.11
by Jonathan Lange
The SMTP config doesn't need to be in vals. |
330 |
'smtp_server = %s\n' % (self._smtp_server,)) |
331 |
if self._smtp_username: |
|
332 |
bazaar_conf_file.write( |
|
333 |
'smtp_username = %s\n' % (self._smtp_username,)) |
|
334 |
if self._smtp_password: |
|
335 |
bazaar_conf_file.write( |
|
336 |
'smtp_password = %s\n' % (self._smtp_password,)) |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
337 |
bazaar_conf_file.close() |
338 |
# Copy remote ec2-remote over
|
|
339 |
self.log('Copying ec2test-remote.py to remote machine.\n') |
|
9550.13.34
by Michael Hudson
make using sftp more convenient |
340 |
user_connection.sftp.put( |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
341 |
os.path.join(os.path.dirname(os.path.realpath(__file__)), |
342 |
'ec2test-remote.py'), |
|
343 |
'/var/launchpad/ec2test-remote.py') |
|
344 |
# Set up launchpad login and email
|
|
9636.1.14
by Jonathan Lange
Drop launchpad-login from the vals dictionary. |
345 |
as_user('bzr launchpad-login %s' % (self._launchpad_login,)) |
9397.1.3
by Michael Hudson
resolve one of Jono's XXXs: make EC2Instance less stateful |
346 |
user_connection.close() |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
347 |
|
348 |
def prepare_tests(self): |
|
9550.13.2
by Michael Hudson
move towards using a pre-setup account |
349 |
user_connection = self._instance.connect() |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
350 |
# Clean up the test branch left in the instance image.
|
9397.1.3
by Michael Hudson
resolve one of Jono's XXXs: make EC2Instance less stateful |
351 |
user_connection.perform('rm -rf /var/launchpad/test') |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
352 |
# Get trunk.
|
9397.1.3
by Michael Hudson
resolve one of Jono's XXXs: make EC2Instance less stateful |
353 |
user_connection.run_with_ssh_agent( |
9636.1.9
by Jonathan Lange
Don't store trunk_branch in vals. It's only needed in one place. |
354 |
'bzr branch %s /var/launchpad/test' % (self._trunk_branch,)) |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
355 |
# Merge the branch in.
|
9636.1.10
by Jonathan Lange
Remove 'branch' from vals, since only the TestRunner uses it. |
356 |
if self._branch is not None: |
9397.1.3
by Michael Hudson
resolve one of Jono's XXXs: make EC2Instance less stateful |
357 |
user_connection.run_with_ssh_agent( |
9636.1.10
by Jonathan Lange
Remove 'branch' from vals, since only the TestRunner uses it. |
358 |
'cd /var/launchpad/test; bzr merge %s' % (self._branch,)) |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
359 |
else: |
360 |
self.log('(Testing trunk, so no branch merge.)') |
|
9550.12.8
by Michael Hudson
null merge trunk r9576 (which reverted merge of this branch) |
361 |
# get newest sources
|
362 |
user_connection.run_with_ssh_agent( |
|
363 |
"/var/launchpad/test/utilities/update-sourcecode "
|
|
364 |
"/var/launchpad/sourcecode") |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
365 |
# Get any new sourcecode branches as requested
|
366 |
for dest, src in self.branches: |
|
367 |
fulldest = os.path.join('/var/launchpad/test/sourcecode', dest) |
|
9964.1.3
by Francis J. Lacoste
Fix from Michael to test c-i-p and shipit branches. |
368 |
# Most sourcecode branches share no history with Launchpad and
|
369 |
# might be in different formats so we "branch --standalone" them
|
|
370 |
# to avoid terribly slow on-the-fly conversions. However, neither
|
|
371 |
# thing is true of canonical-identity or shipit, so we let them
|
|
372 |
# use the Launchpad repository.
|
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
373 |
if dest in ('canonical-identity-provider', 'shipit'): |
9964.1.3
by Francis J. Lacoste
Fix from Michael to test c-i-p and shipit branches. |
374 |
standalone = '' |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
375 |
else: |
9964.1.3
by Francis J. Lacoste
Fix from Michael to test c-i-p and shipit branches. |
376 |
standalone = '--standalone' |
377 |
user_connection.run_with_ssh_agent( |
|
378 |
'bzr branch %s %s %s' % (standalone, src, fulldest)) |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
379 |
# prepare fresh copy of sourcecode and buildout sources for building
|
9397.1.3
by Michael Hudson
resolve one of Jono's XXXs: make EC2Instance less stateful |
380 |
p = user_connection.perform |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
381 |
p('rm -rf /var/launchpad/tmp') |
382 |
p('mkdir /var/launchpad/tmp') |
|
9437.3.3
by Michael Hudson
move the sourcecode, no need to copy it! |
383 |
p('mv /var/launchpad/sourcecode /var/launchpad/tmp/sourcecode') |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
384 |
p('mkdir /var/launchpad/tmp/eggs') |
9397.1.3
by Michael Hudson
resolve one of Jono's XXXs: make EC2Instance less stateful |
385 |
user_connection.run_with_ssh_agent( |
9437.3.4
by Michael Hudson
update the download-cache we now assume is present on the image |
386 |
'bzr pull lp:lp-source-dependencies '
|
387 |
'-d /var/launchpad/download-cache') |
|
388 |
p('mv /var/launchpad/download-cache /var/launchpad/tmp/download-cache') |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
389 |
if (self.include_download_cache_changes and |
390 |
self.download_cache_additions): |
|
391 |
root = os.path.realpath( |
|
392 |
os.path.join(self.original_branch, 'download-cache')) |
|
393 |
for info in self.download_cache_additions: |
|
394 |
src = os.path.join(root, info[0]) |
|
395 |
self.log('Copying %s to remote machine.\n' % (src,)) |
|
9550.13.34
by Michael Hudson
make using sftp more convenient |
396 |
user_connection.sftp.put( |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
397 |
src, |
398 |
os.path.join('/var/launchpad/tmp/download-cache', info[0])) |
|
399 |
p('/var/launchpad/test/utilities/link-external-sourcecode ' |
|
400 |
'-p/var/launchpad/tmp -t/var/launchpad/test'), |
|
401 |
# set up database
|
|
9550.13.29
by Michael Hudson
some more, some less genericity, make the remote user called ec2test |
402 |
p('/var/launchpad/test/utilities/launchpad-database-setup $USER') |
10546.1.2
by Michael Hudson
run tests in ec2 with /var/tmp/launchpad_mailqueue read-only |
403 |
p('mkdir -p /var/tmp/launchpad_mailqueue/cur') |
404 |
p('mkdir -p /var/tmp/launchpad_mailqueue/new') |
|
405 |
p('mkdir -p /var/tmp/launchpad_mailqueue/tmp') |
|
406 |
p('chmod -R a-w /var/tmp/launchpad_mailqueue/') |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
407 |
# close ssh connection
|
9397.1.3
by Michael Hudson
resolve one of Jono's XXXs: make EC2Instance less stateful |
408 |
user_connection.close() |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
409 |
|
9453.2.12
by Michael Hudson
fooey |
410 |
def run_demo_server(self): |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
411 |
"""Turn ec2 instance into a demo server."""
|
9453.2.7
by Michael Hudson
flesh out demo command |
412 |
self.configure_system() |
413 |
self.prepare_tests() |
|
9550.13.2
by Michael Hudson
move towards using a pre-setup account |
414 |
user_connection = self._instance.connect() |
9397.1.3
by Michael Hudson
resolve one of Jono's XXXs: make EC2Instance less stateful |
415 |
p = user_connection.perform |
9453.2.7
by Michael Hudson
flesh out demo command |
416 |
p('make -C /var/launchpad/test schema') |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
417 |
p('mkdir -p /var/tmp/bazaar.launchpad.dev/static') |
418 |
p('mkdir -p /var/tmp/bazaar.launchpad.dev/mirrors') |
|
419 |
p('sudo a2enmod proxy > /dev/null') |
|
420 |
p('sudo a2enmod proxy_http > /dev/null') |
|
421 |
p('sudo a2enmod rewrite > /dev/null') |
|
422 |
p('sudo a2enmod ssl > /dev/null') |
|
423 |
p('sudo a2enmod deflate > /dev/null') |
|
424 |
p('sudo a2enmod headers > /dev/null') |
|
425 |
# Install apache config file.
|
|
426 |
p('cd /var/launchpad/test/; sudo make install') |
|
427 |
# Use raw string to eliminate the need to escape the backslash.
|
|
428 |
# Put eth0's ip address in the /tmp/ip file.
|
|
429 |
p(r"ifconfig eth0 | grep 'inet addr' " |
|
430 |
r"| sed -re 's/.*addr:([0-9.]*) .*/\1/' > /tmp/ip") |
|
431 |
# Replace 127.0.0.88 in Launchpad's apache config file with the
|
|
432 |
# ip address just stored in the /tmp/ip file. Perl allows for
|
|
433 |
# inplace editing unlike sed.
|
|
434 |
p('sudo perl -pi -e "s/127.0.0.88/$(cat /tmp/ip)/g" ' |
|
435 |
'/etc/apache2/sites-available/local-launchpad') |
|
436 |
# Restart apache.
|
|
437 |
p('sudo /etc/init.d/apache2 restart') |
|
438 |
# Build mailman and minified javascript, etc.
|
|
439 |
p('cd /var/launchpad/test/; make') |
|
440 |
# Start launchpad in the background.
|
|
441 |
p('cd /var/launchpad/test/; make start') |
|
442 |
# close ssh connection
|
|
9397.1.3
by Michael Hudson
resolve one of Jono's XXXs: make EC2Instance less stateful |
443 |
user_connection.close() |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
444 |
|
445 |
def run_tests(self): |
|
9453.2.7
by Michael Hudson
flesh out demo command |
446 |
self.configure_system() |
447 |
self.prepare_tests() |
|
9550.13.2
by Michael Hudson
move towards using a pre-setup account |
448 |
user_connection = self._instance.connect() |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
449 |
|
450 |
# Make sure we activate the failsafe --shutdown feature. This will
|
|
451 |
# make the server shut itself down after the test run completes, or
|
|
452 |
# if the test harness suffers a critical failure.
|
|
453 |
cmd = ['python /var/launchpad/ec2test-remote.py --shutdown'] |
|
454 |
||
455 |
# Do we want to email the results to the user?
|
|
456 |
if self.email: |
|
457 |
for email in self.email: |
|
458 |
cmd.append("--email='%s'" % ( |
|
459 |
email.encode('utf8').encode('string-escape'),)) |
|
460 |
||
461 |
# Do we want to submit the branch to PQM if the tests pass?
|
|
462 |
if self.message is not None: |
|
463 |
cmd.append( |
|
464 |
"--submit-pqm-message='%s'" % ( |
|
465 |
pickle.dumps( |
|
466 |
self.message).encode( |
|
467 |
'base64').encode('string-escape'),)) |
|
468 |
||
469 |
# Do we want to disconnect the terminal once the test run starts?
|
|
470 |
if self.headless: |
|
471 |
cmd.append('--daemon') |
|
472 |
||
473 |
# Which branch do we want to test?
|
|
9636.1.10
by Jonathan Lange
Remove 'branch' from vals, since only the TestRunner uses it. |
474 |
if self._branch is not None: |
475 |
branch = self._branch |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
476 |
remote_branch = Branch.open(branch) |
477 |
branch_revno = remote_branch.revno() |
|
478 |
else: |
|
9636.1.9
by Jonathan Lange
Don't store trunk_branch in vals. It's only needed in one place. |
479 |
branch = self._trunk_branch |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
480 |
branch_revno = None |
9636.1.2
by Jonathan Lange
More PEP 8 cleanups |
481 |
cmd.append('--public-branch=%s' % branch) |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
482 |
if branch_revno is not None: |
483 |
cmd.append('--public-branch-revno=%d' % branch_revno) |
|
484 |
||
485 |
# Add any additional options for ec2test-remote.py
|
|
486 |
cmd.extend(self.get_remote_test_options()) |
|
487 |
self.log( |
|
488 |
'Running tests... (output is available on '
|
|
489 |
'http://%s/)\n' % self._instance.hostname) |
|
490 |
||
491 |
# Try opening a browser pointed at the current test results.
|
|
492 |
if self.open_browser: |
|
493 |
try: |
|
494 |
import webbrowser |
|
495 |
except ImportError: |
|
496 |
self.log("Could not open web browser due to ImportError.") |
|
497 |
else: |
|
498 |
status = webbrowser.open(self._instance.hostname) |
|
499 |
if not status: |
|
500 |
self.log("Could not open web browser.") |
|
501 |
||
502 |
# Run the remote script! Our execution will block here until the
|
|
503 |
# remote side disconnects from the terminal.
|
|
9397.1.3
by Michael Hudson
resolve one of Jono's XXXs: make EC2Instance less stateful |
504 |
user_connection.perform(' '.join(cmd)) |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
505 |
self._running = True |
506 |
||
507 |
if not self.headless: |
|
508 |
# We ran to completion locally, so we'll be in charge of shutting
|
|
509 |
# down the instance, in case the user has requested a postmortem.
|
|
510 |
#
|
|
511 |
# We only have 60 seconds to do this before the remote test
|
|
512 |
# script shuts the server down automatically.
|
|
9397.1.3
by Michael Hudson
resolve one of Jono's XXXs: make EC2Instance less stateful |
513 |
user_connection.perform( |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
514 |
'kill `cat /var/launchpad/ec2test-remote.pid`') |
515 |
||
516 |
# deliver results as requested
|
|
517 |
if self.file: |
|
518 |
self.log( |
|
519 |
'Writing abridged test results to %s.\n' % self.file) |
|
9550.13.34
by Michael Hudson
make using sftp more convenient |
520 |
user_connection.sftp.get('/var/www/summary.log', self.file) |
9397.1.10
by Michael Hudson
more fixes |
521 |
user_connection.close() |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
522 |
|
523 |
def get_remote_test_options(self): |
|
524 |
"""Return the test command that will be passed to ec2test-remote.py.
|
|
525 |
||
526 |
Returns a tuple of command-line options and switches.
|
|
527 |
"""
|
|
528 |
if '--jscheck' in self.test_options: |
|
529 |
# We want to run the JavaScript test suite.
|
|
530 |
return ('--jscheck',) |
|
531 |
else: |
|
532 |
# Run the normal testsuite with our Zope testrunner options.
|
|
533 |
# ec2test-remote.py wants the extra options to be after a double-
|
|
534 |
# dash.
|
|
535 |
return ('--', self.test_options) |