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 |
||
10189.6.17
by Jonathan Lange
Get rid of other silly -vv options. |
112 |
def __init__(self, branch, email=False, file=None, test_options=None, |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
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') |
10224.3.2
by Martin Pool
Clarify ec2 requirement for an smtp server |
292 |
# Refuse localhost, because there's no SMTP server _on the actual
|
293 |
# EC2 instance._
|
|
9636.1.11
by Jonathan Lange
The SMTP config doesn't need to be in vals. |
294 |
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 |
295 |
raise ValueError( |
296 |
'To send email, a remotely accessible smtp_server (and '
|
|
297 |
'smtp_username and smtp_password, if necessary) must be '
|
|
298 |
'configured in bzr. See the SMTP server information '
|
|
10224.3.2
by Martin Pool
Clarify ec2 requirement for an smtp server |
299 |
'here: https://wiki.canonical.com/EmailSetup .'
|
300 |
'This server must be reachable from the EC2 instance.') |
|
9636.1.11
by Jonathan Lange
The SMTP config doesn't need to be in vals. |
301 |
self._smtp_username = config.get_user_option('smtp_username') |
302 |
self._smtp_password = config.get_user_option('smtp_password') |
|
10542.2.1
by Jelmer Vernooij
Use configured email address in Bazaar as From address. |
303 |
self._from_email = config.username() |
304 |
if not self._from_email: |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
305 |
raise ValueError( |
306 |
'To send email, your bzr email address must be set '
|
|
307 |
'(use ``bzr whoami``).') |
|
308 |
||
9397.2.5
by Michael Hudson
move a bunch of code from somewhere where it doesn't belong to somewhere else |
309 |
self._instance = instance |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
310 |
|
311 |
def log(self, msg): |
|
312 |
"""Log a message on stdout, flushing afterwards."""
|
|
313 |
# XXX: JonathanLange 2009-05-31 bug=383076: This should use Python
|
|
314 |
# logging, rather than printing to stdout.
|
|
315 |
sys.stdout.write(msg) |
|
316 |
sys.stdout.flush() |
|
317 |
||
318 |
def configure_system(self): |
|
9550.13.2
by Michael Hudson
move towards using a pre-setup account |
319 |
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' |
320 |
if self.timeout is not None: |
11346.1.2
by Maris Fogels
Dropped the fail-safe timeout from 8 hours to 5. Added a comment while I was at it. |
321 |
# Activate a fail-safe shutdown just in case something goes
|
322 |
# really wrong with the server or suite.
|
|
11346.1.3
by Maris Fogels
More comments for the code, based on reviewer feedback. |
323 |
#
|
324 |
# We need to use a call to /usr/bin/at here instead of a call to
|
|
325 |
# /sbin/shutdown because the test suite already uses the shutdown
|
|
326 |
# command after the suite finishes. If we called shutdown
|
|
327 |
# here, it would prevent the end-of-suite shutdown from executing,
|
|
328 |
# leaving the server running until the failsafe finally activates.
|
|
329 |
# See bug 617598 for the details.
|
|
11346.1.1
by Maris Fogels
Backed out revision 11224. This fixes a bug where one shutdown call blocks the suite-ending shutdown call from succeeding. |
330 |
user_connection.perform( |
331 |
"echo sudo shutdown -h now | at today + %d minutes" |
|
332 |
% self.timeout) |
|
9397.1.14
by Michael Hudson
user_p -> as_user, root_p -> as_root |
333 |
as_user = user_connection.perform |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
334 |
# Set up bazaar.conf with smtp information if necessary
|
335 |
if self.email or self.message: |
|
10271.3.3
by Michael Hudson
another fix... |
336 |
as_user('[ -d .bazaar ] || mkdir .bazaar') |
9550.13.34
by Michael Hudson
make using sftp more convenient |
337 |
bazaar_conf_file = user_connection.sftp.open( |
9550.13.40
by Michael Hudson
self-review-ish comments |
338 |
".bazaar/bazaar.conf", 'w') |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
339 |
bazaar_conf_file.write( |
10697.1.1
by Maris Fogels
Fix a bug where unicode email addresses with international characters in them raise an error when they are copied to the remote bazaar.conf via SFTP. |
340 |
'email = %s\n' % (self._from_email.encode('utf-8'),)) |
10542.2.1
by Jelmer Vernooij
Use configured email address in Bazaar as From address. |
341 |
bazaar_conf_file.write( |
9636.1.11
by Jonathan Lange
The SMTP config doesn't need to be in vals. |
342 |
'smtp_server = %s\n' % (self._smtp_server,)) |
343 |
if self._smtp_username: |
|
344 |
bazaar_conf_file.write( |
|
345 |
'smtp_username = %s\n' % (self._smtp_username,)) |
|
346 |
if self._smtp_password: |
|
347 |
bazaar_conf_file.write( |
|
348 |
'smtp_password = %s\n' % (self._smtp_password,)) |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
349 |
bazaar_conf_file.close() |
350 |
# Copy remote ec2-remote over
|
|
10766.6.1
by Jonathan Lange
Give the ec2test-remote script an easily-importable name so we can test it. |
351 |
self.log('Copying remote.py to remote machine.\n') |
9550.13.34
by Michael Hudson
make using sftp more convenient |
352 |
user_connection.sftp.put( |
10766.6.1
by Jonathan Lange
Give the ec2test-remote script an easily-importable name so we can test it. |
353 |
os.path.join( |
354 |
os.path.dirname(os.path.realpath(__file__)), 'remote.py'), |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
355 |
'/var/launchpad/ec2test-remote.py') |
356 |
# Set up launchpad login and email
|
|
9636.1.14
by Jonathan Lange
Drop launchpad-login from the vals dictionary. |
357 |
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 |
358 |
user_connection.close() |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
359 |
|
360 |
def prepare_tests(self): |
|
9550.13.2
by Michael Hudson
move towards using a pre-setup account |
361 |
user_connection = self._instance.connect() |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
362 |
# 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 |
363 |
user_connection.perform('rm -rf /var/launchpad/test') |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
364 |
# Get trunk.
|
9397.1.3
by Michael Hudson
resolve one of Jono's XXXs: make EC2Instance less stateful |
365 |
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. |
366 |
'bzr branch %s /var/launchpad/test' % (self._trunk_branch,)) |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
367 |
# Merge the branch in.
|
9636.1.10
by Jonathan Lange
Remove 'branch' from vals, since only the TestRunner uses it. |
368 |
if self._branch is not None: |
9397.1.3
by Michael Hudson
resolve one of Jono's XXXs: make EC2Instance less stateful |
369 |
user_connection.run_with_ssh_agent( |
9636.1.10
by Jonathan Lange
Remove 'branch' from vals, since only the TestRunner uses it. |
370 |
'cd /var/launchpad/test; bzr merge %s' % (self._branch,)) |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
371 |
else: |
372 |
self.log('(Testing trunk, so no branch merge.)') |
|
9550.12.8
by Michael Hudson
null merge trunk r9576 (which reverted merge of this branch) |
373 |
# get newest sources
|
374 |
user_connection.run_with_ssh_agent( |
|
375 |
"/var/launchpad/test/utilities/update-sourcecode "
|
|
376 |
"/var/launchpad/sourcecode") |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
377 |
# Get any new sourcecode branches as requested
|
378 |
for dest, src in self.branches: |
|
379 |
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. |
380 |
# Most sourcecode branches share no history with Launchpad and
|
381 |
# might be in different formats so we "branch --standalone" them
|
|
382 |
# to avoid terribly slow on-the-fly conversions. However, neither
|
|
383 |
# thing is true of canonical-identity or shipit, so we let them
|
|
384 |
# use the Launchpad repository.
|
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
385 |
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. |
386 |
standalone = '' |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
387 |
else: |
9964.1.3
by Francis J. Lacoste
Fix from Michael to test c-i-p and shipit branches. |
388 |
standalone = '--standalone' |
389 |
user_connection.run_with_ssh_agent( |
|
390 |
'bzr branch %s %s %s' % (standalone, src, fulldest)) |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
391 |
# 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 |
392 |
p = user_connection.perform |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
393 |
p('rm -rf /var/launchpad/tmp') |
394 |
p('mkdir /var/launchpad/tmp') |
|
9437.3.3
by Michael Hudson
move the sourcecode, no need to copy it! |
395 |
p('mv /var/launchpad/sourcecode /var/launchpad/tmp/sourcecode') |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
396 |
p('mkdir /var/launchpad/tmp/eggs') |
9397.1.3
by Michael Hudson
resolve one of Jono's XXXs: make EC2Instance less stateful |
397 |
user_connection.run_with_ssh_agent( |
9437.3.4
by Michael Hudson
update the download-cache we now assume is present on the image |
398 |
'bzr pull lp:lp-source-dependencies '
|
399 |
'-d /var/launchpad/download-cache') |
|
400 |
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 |
401 |
if (self.include_download_cache_changes and |
402 |
self.download_cache_additions): |
|
403 |
root = os.path.realpath( |
|
404 |
os.path.join(self.original_branch, 'download-cache')) |
|
405 |
for info in self.download_cache_additions: |
|
406 |
src = os.path.join(root, info[0]) |
|
407 |
self.log('Copying %s to remote machine.\n' % (src,)) |
|
9550.13.34
by Michael Hudson
make using sftp more convenient |
408 |
user_connection.sftp.put( |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
409 |
src, |
410 |
os.path.join('/var/launchpad/tmp/download-cache', info[0])) |
|
411 |
p('/var/launchpad/test/utilities/link-external-sourcecode ' |
|
412 |
'-p/var/launchpad/tmp -t/var/launchpad/test'), |
|
413 |
# set up database
|
|
9550.13.29
by Michael Hudson
some more, some less genericity, make the remote user called ec2test |
414 |
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 |
415 |
p('mkdir -p /var/tmp/launchpad_mailqueue/cur') |
416 |
p('mkdir -p /var/tmp/launchpad_mailqueue/new') |
|
417 |
p('mkdir -p /var/tmp/launchpad_mailqueue/tmp') |
|
418 |
p('chmod -R a-w /var/tmp/launchpad_mailqueue/') |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
419 |
# close ssh connection
|
9397.1.3
by Michael Hudson
resolve one of Jono's XXXs: make EC2Instance less stateful |
420 |
user_connection.close() |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
421 |
|
9453.2.12
by Michael Hudson
fooey |
422 |
def run_demo_server(self): |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
423 |
"""Turn ec2 instance into a demo server."""
|
9453.2.7
by Michael Hudson
flesh out demo command |
424 |
self.configure_system() |
425 |
self.prepare_tests() |
|
9550.13.2
by Michael Hudson
move towards using a pre-setup account |
426 |
user_connection = self._instance.connect() |
9397.1.3
by Michael Hudson
resolve one of Jono's XXXs: make EC2Instance less stateful |
427 |
p = user_connection.perform |
9453.2.7
by Michael Hudson
flesh out demo command |
428 |
p('make -C /var/launchpad/test schema') |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
429 |
p('mkdir -p /var/tmp/bazaar.launchpad.dev/static') |
430 |
p('mkdir -p /var/tmp/bazaar.launchpad.dev/mirrors') |
|
431 |
p('sudo a2enmod proxy > /dev/null') |
|
432 |
p('sudo a2enmod proxy_http > /dev/null') |
|
433 |
p('sudo a2enmod rewrite > /dev/null') |
|
434 |
p('sudo a2enmod ssl > /dev/null') |
|
435 |
p('sudo a2enmod deflate > /dev/null') |
|
436 |
p('sudo a2enmod headers > /dev/null') |
|
437 |
# Install apache config file.
|
|
438 |
p('cd /var/launchpad/test/; sudo make install') |
|
439 |
# Use raw string to eliminate the need to escape the backslash.
|
|
440 |
# Put eth0's ip address in the /tmp/ip file.
|
|
441 |
p(r"ifconfig eth0 | grep 'inet addr' " |
|
442 |
r"| sed -re 's/.*addr:([0-9.]*) .*/\1/' > /tmp/ip") |
|
443 |
# Replace 127.0.0.88 in Launchpad's apache config file with the
|
|
444 |
# ip address just stored in the /tmp/ip file. Perl allows for
|
|
445 |
# inplace editing unlike sed.
|
|
446 |
p('sudo perl -pi -e "s/127.0.0.88/$(cat /tmp/ip)/g" ' |
|
447 |
'/etc/apache2/sites-available/local-launchpad') |
|
448 |
# Restart apache.
|
|
449 |
p('sudo /etc/init.d/apache2 restart') |
|
450 |
# Build mailman and minified javascript, etc.
|
|
451 |
p('cd /var/launchpad/test/; make') |
|
452 |
# Start launchpad in the background.
|
|
453 |
p('cd /var/launchpad/test/; make start') |
|
454 |
# close ssh connection
|
|
9397.1.3
by Michael Hudson
resolve one of Jono's XXXs: make EC2Instance less stateful |
455 |
user_connection.close() |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
456 |
|
11128.13.58
by Jonathan Lange
Add a way to get very very close to running the tests. |
457 |
def _build_command(self): |
458 |
"""Build the command that we'll use to run the tests."""
|
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
459 |
# Make sure we activate the failsafe --shutdown feature. This will
|
460 |
# make the server shut itself down after the test run completes, or
|
|
461 |
# if the test harness suffers a critical failure.
|
|
462 |
cmd = ['python /var/launchpad/ec2test-remote.py --shutdown'] |
|
463 |
||
464 |
# Do we want to email the results to the user?
|
|
465 |
if self.email: |
|
466 |
for email in self.email: |
|
467 |
cmd.append("--email='%s'" % ( |
|
468 |
email.encode('utf8').encode('string-escape'),)) |
|
469 |
||
470 |
# Do we want to submit the branch to PQM if the tests pass?
|
|
471 |
if self.message is not None: |
|
472 |
cmd.append( |
|
473 |
"--submit-pqm-message='%s'" % ( |
|
474 |
pickle.dumps( |
|
475 |
self.message).encode( |
|
476 |
'base64').encode('string-escape'),)) |
|
477 |
||
478 |
# Do we want to disconnect the terminal once the test run starts?
|
|
479 |
if self.headless: |
|
480 |
cmd.append('--daemon') |
|
481 |
||
482 |
# Which branch do we want to test?
|
|
9636.1.10
by Jonathan Lange
Remove 'branch' from vals, since only the TestRunner uses it. |
483 |
if self._branch is not None: |
484 |
branch = self._branch |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
485 |
remote_branch = Branch.open(branch) |
486 |
branch_revno = remote_branch.revno() |
|
487 |
else: |
|
9636.1.9
by Jonathan Lange
Don't store trunk_branch in vals. It's only needed in one place. |
488 |
branch = self._trunk_branch |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
489 |
branch_revno = None |
9636.1.2
by Jonathan Lange
More PEP 8 cleanups |
490 |
cmd.append('--public-branch=%s' % branch) |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
491 |
if branch_revno is not None: |
492 |
cmd.append('--public-branch-revno=%d' % branch_revno) |
|
493 |
||
494 |
# Add any additional options for ec2test-remote.py
|
|
10189.6.5
by Jonathan Lange
Remove the unused JSCheckTestRunner. |
495 |
cmd.extend(['--', self.test_options]) |
11128.13.58
by Jonathan Lange
Add a way to get very very close to running the tests. |
496 |
return ' '.join(cmd) |
497 |
||
498 |
def run_tests(self): |
|
499 |
self.configure_system() |
|
500 |
self.prepare_tests() |
|
501 |
||
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
502 |
self.log( |
503 |
'Running tests... (output is available on '
|
|
504 |
'http://%s/)\n' % self._instance.hostname) |
|
505 |
||
506 |
# Try opening a browser pointed at the current test results.
|
|
507 |
if self.open_browser: |
|
508 |
try: |
|
509 |
import webbrowser |
|
510 |
except ImportError: |
|
511 |
self.log("Could not open web browser due to ImportError.") |
|
512 |
else: |
|
513 |
status = webbrowser.open(self._instance.hostname) |
|
514 |
if not status: |
|
515 |
self.log("Could not open web browser.") |
|
516 |
||
517 |
# Run the remote script! Our execution will block here until the
|
|
518 |
# remote side disconnects from the terminal.
|
|
11128.13.58
by Jonathan Lange
Add a way to get very very close to running the tests. |
519 |
cmd = self._build_command() |
520 |
user_connection = self._instance.connect() |
|
521 |
user_connection.perform(cmd) |
|
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
522 |
self._running = True |
523 |
||
524 |
if not self.headless: |
|
525 |
# We ran to completion locally, so we'll be in charge of shutting
|
|
526 |
# down the instance, in case the user has requested a postmortem.
|
|
527 |
#
|
|
528 |
# We only have 60 seconds to do this before the remote test
|
|
529 |
# script shuts the server down automatically.
|
|
9397.1.3
by Michael Hudson
resolve one of Jono's XXXs: make EC2Instance less stateful |
530 |
user_connection.perform( |
9389.6.5
by Michael Hudson
move EC2Credentials and EC2TestRunner to their own files |
531 |
'kill `cat /var/launchpad/ec2test-remote.pid`') |
532 |
||
533 |
# deliver results as requested
|
|
534 |
if self.file: |
|
535 |
self.log( |
|
536 |
'Writing abridged test results to %s.\n' % self.file) |
|
9550.13.34
by Michael Hudson
make using sftp more convenient |
537 |
user_connection.sftp.get('/var/www/summary.log', self.file) |
9397.1.10
by Michael Hudson
more fixes |
538 |
user_connection.close() |