Merge lp:~bac/lpsetup/fix-inithost-install-lxc into lp:lpsetup
- fix-inithost-install-lxc
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Gary Poster |
Approved revision: | 60 |
Merged at revision: | 52 |
Proposed branch: | lp:~bac/lpsetup/fix-inithost-install-lxc |
Merge into: | lp:lpsetup |
Diff against target: |
941 lines (+224/-301) 17 files modified
README.rst (+11/-3) lplxcip/tests/utils.py (+1/-1) lpsetup/handlers.py (+7/-4) lpsetup/settings.py (+3/-1) lpsetup/subcommands/finish_inithost.py (+48/-94) lpsetup/subcommands/inithost.py (+15/-4) lpsetup/subcommands/initlxc.py (+7/-2) lpsetup/subcommands/initrepo.py (+16/-3) lpsetup/subcommands/install_lxc.py (+54/-116) lpsetup/subcommands/update.py (+17/-13) lpsetup/tests/subcommands/test_finish_inithost.py (+8/-22) lpsetup/tests/subcommands/test_inithost.py (+1/-1) lpsetup/tests/subcommands/test_initlxc.py (+2/-2) lpsetup/tests/subcommands/test_install_lxc.py (+26/-27) lpsetup/tests/subcommands/test_update.py (+2/-1) pre-commit.sh (+1/-1) setup.cfg (+5/-6) |
To merge this branch: | bzr merge lp:~bac/lpsetup/fix-inithost-install-lxc |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gary Poster (community) | Approve | ||
Review via email: mp+114486@code.launchpad.net |
Commit message
Fix install-lxc and finish-init-host.
Description of the change
A previous branch refactored away some methods that install-lxc and finish-init-host needed. Those commands were neutered and their tests disabled.
This branch fixes them properly. Some stuff from finish-init-host was moved to init-host so that everything in the latter stage all depend upon a Launchpad tree existing.
I poked and prodded setup.cfg and with Francesco's help got a work-around that seems to appease nose.
Brad Crittenden (bac) wrote : | # |
- 54. By Brad Crittenden
-
Fix fatal typo
- 55. By Brad Crittenden
-
Don't error if launchpad repo already exists
- 56. By Brad Crittenden
-
Fix typo
Gary Poster (gary) wrote : | # |
Hi Brad. Thank you, this looks very good.
I believe the make_launchpad is called only once, with install=True. This suggests that we could remove that argument from the signature; and it further suggests that we could maybe collapse it into setup_launchpad. Take that as far as you feel comfortable.
I think it would be nice if finish-inithost had a docstring (and help text?) that indicated that it was slated for eventual removal.
The only "must-have" change I have is that install_lxc should not include inithost.
Thanks again!
Gary
Gary Poster (gary) wrote : | # |
Brad and I talked further. install-lxc still needs some more refactoring. he'll circle around and finish that up.
- 57. By Brad Crittenden
-
Added notes on broken install-lxc
- 58. By Brad Crittenden
-
checkpoint
- 59. By Brad Crittenden
-
Fixes to install_lxc.
- 60. By Brad Crittenden
-
Finish up install-lxc and make changes due to testing. Made command-line options unique.
Brad Crittenden (bac) wrote : | # |
Gary please look at this again.
Gary Poster (gary) wrote : | # |
Wow, thank you Brad. This is great. Everything from the code cleanup, to the code reduction, to the help & doc text improvements are really wonderful.
Could you please make a card, or a quick branch, to have handle_directories use os.path.abspath so we can pass directories like '.'?
The help for the user argument of finish-init-host does not make sense right now. Could you arrange for it to be adjusted to remove references to creating a user, unless you disagree?
Francesco Banconi (frankban) wrote : | # |
Gary wrote:
> Could you please make a card, or a quick branch, to have handle_directories use os.path.abspath
> so we can pass directories like '.'?
Yesterday I made this change in the branch I am currently working on: I thought that being able to pass relative paths (e.g. to init-repo) is a really nice thing to have.
Brad Crittenden (bac) wrote : | # |
Thanks Gary.
Changes being made in a different branch and merge proposal.
Preview Diff
1 | === modified file 'README.rst' |
2 | --- README.rst 2012-07-10 20:00:37 +0000 |
3 | +++ README.rst 2012-07-12 22:14:19 +0000 |
4 | @@ -11,7 +11,14 @@ |
5 | ~~~~~~~~~~~~ |
6 | |
7 | lp-setup requires: |
8 | -Python >= 2.7, `python-shelltoolbox`, and `pep8`. |
9 | + lxc |
10 | + Python >= 2.7 |
11 | + pep8 |
12 | + python-shelltoolbox |
13 | + python-pocket-lint |
14 | + python-nose |
15 | + python-coverage (optional) |
16 | + |
17 | The package `python-argparse` is required to run lp-setup using Python 2.6. |
18 | |
19 | |
20 | @@ -40,8 +47,10 @@ |
21 | |
22 | To run *lpsetup* tests install nose and run `nosetests` from this directory:: |
23 | |
24 | - apt-get install python-nose |
25 | + apt-get install python-nose python-coverage |
26 | nosetests |
27 | + or |
28 | + ./pre-commit.sh |
29 | |
30 | |
31 | Integration tests |
32 | @@ -69,7 +78,6 @@ |
33 | |
34 | Install pocketlint:: |
35 | |
36 | - sudo apt-add-repository ppa:sinzui/ppa |
37 | sudo apt-get update |
38 | sudo apt-get install python-pocket-lint |
39 | |
40 | |
41 | === modified file 'lplxcip/tests/utils.py' |
42 | --- lplxcip/tests/utils.py 2012-05-03 14:20:13 +0000 |
43 | +++ lplxcip/tests/utils.py 2012-07-12 22:14:19 +0000 |
44 | @@ -87,7 +87,7 @@ |
45 | '-n', self.name, |
46 | '-f', self._write_config(), |
47 | '--', |
48 | - '-r {} -a {}'.format(self.release, self.arch) |
49 | + '-R {} -a {}'.format(self.release, self.arch), |
50 | ] |
51 | return self._call(cmd) |
52 | |
53 | |
54 | === modified file 'lpsetup/handlers.py' |
55 | --- lpsetup/handlers.py 2012-07-10 18:11:30 +0000 |
56 | +++ lpsetup/handlers.py 2012-07-12 22:14:19 +0000 |
57 | @@ -220,18 +220,21 @@ |
58 | |
59 | |
60 | def handle_directories(namespace): |
61 | - """Handle checkout and dependencies directories. |
62 | + """Handle repository, code_dir, and dependencies directories. |
63 | |
64 | - The ~ construction is automatically expanded. |
65 | - The validation fails for directories not residing inside the home. |
66 | - The validation fails if the directory contains spaces. |
67 | """ |
68 | - if ' ' in namespace.repository: |
69 | - raise ValidationError('argument directory can not contain spaces.') |
70 | - for attr in ('repository', 'dependencies_dir'): |
71 | + for attr in ('repository', 'code_dir', 'dependencies_dir'): |
72 | directory = getattr(namespace, attr, None) |
73 | if directory is None: |
74 | continue |
75 | + if ' ' in directory: |
76 | + err = ("argument directory cannot contain " |
77 | + "spaces: '{0}'".format(directory)) |
78 | + raise ValidationError(err) |
79 | + |
80 | directory = directory.replace('~', namespace.home_dir) |
81 | if not directory.startswith(namespace.home_dir + os.path.sep): |
82 | raise ValidationError( |
83 | |
84 | === modified file 'lpsetup/settings.py' |
85 | --- lpsetup/settings.py 2012-07-10 15:50:26 +0000 |
86 | +++ lpsetup/settings.py 2012-07-12 22:14:19 +0000 |
87 | @@ -3,6 +3,7 @@ |
88 | # GNU Affero General Public License version 3 (see the file LICENSE). |
89 | |
90 | """Global settings and defaults for lpsetup.""" |
91 | +import os.path |
92 | |
93 | |
94 | APT_REPOSITORIES = ( |
95 | @@ -53,12 +54,13 @@ |
96 | } |
97 | LP_BRANCH_NAME = 'devel' |
98 | LP_CHECKOUT_NAME = 'sandbox' |
99 | +LP_CODE_DIR = os.path.join(CHECKOUT_DIR, LP_CHECKOUT_NAME) |
100 | LP_PACKAGES = [ |
101 | # "launchpad-database-dependencies-9.1" can be removed once 8.x is |
102 | # no longer an option in "launchpad-developer-dependencies. |
103 | 'launchpad-database-dependencies-9.1', |
104 | 'launchpad-developer-dependencies', 'apache2', |
105 | - 'apache2-mpm-worker', 'libapache2-mod-wsgi' |
106 | + 'apache2-mpm-worker', 'libapache2-mod-wsgi', |
107 | ] |
108 | LP_HTTP_REPO = 'http://bazaar.launchpad.net/~launchpad-pqm/launchpad/devel' |
109 | LP_SSH_REPO = 'lp:launchpad' |
110 | |
111 | === modified file 'lpsetup/subcommands/finish_inithost.py' |
112 | --- lpsetup/subcommands/finish_inithost.py 2012-07-10 15:41:13 +0000 |
113 | +++ lpsetup/subcommands/finish_inithost.py 2012-07-12 22:14:19 +0000 |
114 | @@ -7,11 +7,12 @@ |
115 | Perform all tasks required to be run to initialize a Launchpad development |
116 | host that need to be done 1) after the Launchpad tree has been retrieved and |
117 | 2) run as root. |
118 | + |
119 | +This subcommand is slated for eventual removal. |
120 | """ |
121 | |
122 | __metaclass__ = type |
123 | __all__ = [ |
124 | - 'setup_bzr_locations_as_root', |
125 | 'setup_launchpad', |
126 | 'SubCommand', |
127 | ] |
128 | @@ -19,7 +20,6 @@ |
129 | from contextlib import nested |
130 | import os |
131 | import pwd |
132 | -import subprocess |
133 | |
134 | from shelltoolbox import ( |
135 | cd, |
136 | @@ -27,116 +27,70 @@ |
137 | su, |
138 | ) |
139 | |
140 | -from lpsetup.handlers import handle_directories |
141 | -from lpsetup.subcommands import ( |
142 | - inithost, |
143 | - initrepo, |
144 | - ) |
145 | -from lpsetup.settings import ( |
146 | - CHECKOUT_DIR, |
147 | - DEPENDENCIES_DIR, |
148 | - LP_BRANCH_NAME, |
149 | - ) |
150 | +from lpsetup import argparser |
151 | +from lpsetup.handlers import ( |
152 | + handle_directories, |
153 | + handle_user, |
154 | + ) |
155 | +from lpsetup.settings import LP_CODE_DIR |
156 | from lpsetup.utils import call |
157 | |
158 | |
159 | -def make_launchpad(user, checkout_dir, install=False): |
160 | - """Make and optionally install Launchpad.""" |
161 | - # Using real su because mailman make script uses uid. |
162 | - call(*get_su_command(user, ['make', '-C', checkout_dir])) |
163 | - if install: |
164 | - call('make', '-C', checkout_dir, 'install') |
165 | - |
166 | - |
167 | -def setup_external_sourcecode( |
168 | - user, sandbox_dir, checkout_dir, dependencies_dir, valid_ssh_keys=True): |
169 | - """Update and link external sourcecode.""" |
170 | - cmd = ( |
171 | - 'utilities/update-sourcecode', |
172 | - None if valid_ssh_keys else '--use-http', |
173 | - os.path.join(dependencies_dir, 'sourcecode'), |
174 | - ) |
175 | - if os.path.exists(sandbox_dir): |
176 | - build_dir = sandbox_dir |
177 | - elif os.path.exists(checkout_dir): |
178 | - build_dir = checkout_dir |
179 | - |
180 | - with cd(build_dir): |
181 | - # Using real su because update-sourcecode uses uid. |
182 | - call(*get_su_command(user, cmd)) |
183 | - with su(user): |
184 | - call('utilities/link-external-sourcecode', dependencies_dir) |
185 | - |
186 | - |
187 | -def setup_launchpad(user, dependencies_dir, repository, valid_ssh_keys): |
188 | +def setup_launchpad(user, code_dir): |
189 | """Set up the Launchpad environment.""" |
190 | - # User configuration. |
191 | - subprocess.call(['adduser', user, 'sudo']) |
192 | - pwd_database = pwd.getpwnam(user) |
193 | - subprocess.call(['addgroup', '--gid', str(pwd_database.pw_gid), user]) |
194 | - # Set up Launchpad dependencies. |
195 | - # XXX: Eventually move to 'update'. |
196 | - checkout_dir = os.path.join(repository, LP_BRANCH_NAME) |
197 | - setup_external_sourcecode( |
198 | - user, checkout_dir, dependencies_dir, valid_ssh_keys) |
199 | |
200 | # Launchpad database setup. |
201 | # nested is required for use by python 2.6. |
202 | - with nested(su(user), cd(checkout_dir)): |
203 | + with nested(su(user), cd(code_dir)): |
204 | call('utilities/launchpad-database-setup', user) |
205 | |
206 | # Make and install launchpad. |
207 | - make_launchpad(user, checkout_dir, install=True) |
208 | + with cd(code_dir): |
209 | + # Using real su because mailman make script uses uid. |
210 | + call(*get_su_command(user, ['make', 'schema'])) |
211 | + call('make', 'install') |
212 | |
213 | # Change owner of /srv/launchpad.dev/. |
214 | + pwd_database = pwd.getpwnam(user) |
215 | os.chown('/srv/launchpad.dev/', pwd_database.pw_uid, pwd_database.pw_gid) |
216 | |
217 | |
218 | -def setup_bzr_locations_as_root(user, lpuser, repository): |
219 | - with su(user): |
220 | - initrepo.setup_bzr_locations(lpuser, repository) |
221 | - |
222 | - |
223 | -class SubCommand(inithost.SubCommand): |
224 | - """Finish the initialization of a Launchpad development host.""" |
225 | - |
226 | - # The steps for "install" are a superset of the steps for "inithost". |
227 | +class SubCommand(argparser.StepsBasedSubCommand): |
228 | + """Finish the initialization of a Launchpad development host. |
229 | + |
230 | + Run the commands as root in the Launchpad target machine that must be done |
231 | + after the Launchpad tree is available. |
232 | + |
233 | + This subcommand is slated for eventual removal. |
234 | + """ |
235 | |
236 | help = __doc__ |
237 | |
238 | - @property |
239 | - def steps(self): |
240 | - # Break import loop (and break it here because this subcommand is |
241 | - # going away soon). |
242 | - import install_lxc |
243 | - return ( |
244 | - inithost.SubCommand.initialize_step, |
245 | - install_lxc.SubCommand.fetch_step, |
246 | - (setup_bzr_locations_as_root, |
247 | - 'user', 'lpuser', 'repository'), |
248 | - inithost.SubCommand.setup_apt_step, |
249 | - (setup_launchpad, |
250 | - 'user', 'dependencies_dir', 'repository', 'valid_ssh_keys'), |
251 | - ) |
252 | - |
253 | - def get_handlers(self, namespace): |
254 | - handlers = super(SubCommand, self).get_handlers(namespace) |
255 | - return handlers + (handle_directories,) |
256 | + needs_root = True |
257 | + |
258 | + steps = ( |
259 | + (setup_launchpad, 'user', 'code_dir'), |
260 | + ) |
261 | + |
262 | + handlers = ( |
263 | + handle_user, |
264 | + handle_directories, |
265 | + ) |
266 | + |
267 | + @staticmethod |
268 | + def add_common_arguments(parser): |
269 | + parser.add_argument( |
270 | + '-c', '--code-dir', default=LP_CODE_DIR, |
271 | + help='The directory of the Launchpad code checkout. ' |
272 | + 'The directory must reside under the home directory of the ' |
273 | + 'given user (see -u argument). ' |
274 | + '[DEFAULT={0}]'.format(LP_CODE_DIR)) |
275 | |
276 | def add_arguments(self, parser): |
277 | super(SubCommand, self).add_arguments(parser) |
278 | - parser.add_argument( |
279 | - '-d', '--dependencies-dir', default=DEPENDENCIES_DIR, |
280 | - help='The directory of the Launchpad dependencies to be created. ' |
281 | - 'The directory must reside under the home directory of the ' |
282 | - 'given user (see -u argument). ' |
283 | - '[DEFAULT={0}]'.format(DEPENDENCIES_DIR)) |
284 | - parser.add_argument( |
285 | - '-r', '--repository', default=CHECKOUT_DIR, |
286 | - help='The directory of the Launchpad repository to be created. ' |
287 | - 'The directory must reside under the home directory of the ' |
288 | - 'given user (see -u argument). ' |
289 | - '[DEFAULT={0}]'.format(CHECKOUT_DIR)) |
290 | - parser.add_argument( |
291 | - '-t', '--with-trees', action='store_false', dest='lightweight', |
292 | - default=True, help='Do not use a lightweight checkout.') |
293 | + self.add_common_arguments(parser) |
294 | + parser.add_argument( |
295 | + '-u', '--user', |
296 | + help='The name of the system user to be created or updated. ' |
297 | + 'The current user is used if this script is not run as ' |
298 | + 'root and this argument is omitted.') |
299 | |
300 | === modified file 'lpsetup/subcommands/inithost.py' |
301 | --- lpsetup/subcommands/inithost.py 2012-07-11 11:25:22 +0000 |
302 | +++ lpsetup/subcommands/inithost.py 2012-07-12 22:14:19 +0000 |
303 | @@ -14,6 +14,7 @@ |
304 | |
305 | from email.Utils import formataddr |
306 | import os |
307 | +import pwd |
308 | import shutil |
309 | import subprocess |
310 | |
311 | @@ -109,6 +110,12 @@ |
312 | if not user_exists(user): |
313 | call('useradd', '-m', '-s', '/bin/bash', '-U', user) |
314 | |
315 | + # Add user to the sudo group. |
316 | + subprocess.call(['adduser', user, 'sudo']) |
317 | + # Add the user to his own group. |
318 | + pwd_database = pwd.getpwnam(user) |
319 | + subprocess.call(['addgroup', '--gid', str(pwd_database.pw_gid), user]) |
320 | + |
321 | |
322 | def initialize( |
323 | user, full_name, email, lpuser, private_key, public_key, valid_ssh_keys, |
324 | @@ -146,16 +153,20 @@ |
325 | # XXX benji 2012-03-19 bug=959352: this is so graphviz will work in an |
326 | # ephemeral container |
327 | mkdirs('/rootfs/usr/lib') |
328 | - os.symlink('/usr/lib/graphviz', '/rootfs/usr/lib/graphviz') |
329 | + dst = '/rootfs/usr/lib/graphviz' |
330 | + if not os.path.exists(dst): |
331 | + os.symlink('/usr/lib/graphviz', dst) |
332 | # XXX gary 2012-06-26 bug=1014916: this fixes a bug in Lucid LXC |
333 | # containers. |
334 | if lxc_os == 'lucid': |
335 | # Change /var/lib/lxc/lptests/rootfs/etc/init/networking.conf to not |
336 | # wait for udev (that is, use start on (local-filesystems)). |
337 | udevtrigger = '/etc/init/udevtrigger.conf' |
338 | - shutil.move(udevtrigger, udevtrigger + '.orig') |
339 | + if os.path.exists(udevtrigger): |
340 | + shutil.move(udevtrigger, udevtrigger + '.orig') |
341 | networking = '/etc/init/networking.conf' |
342 | - shutil.move(networking, networking + '.orig') |
343 | + if not os.path.exists(networking + '.orig'): |
344 | + shutil.move(networking, networking + '.orig') |
345 | render_to_file('networking.conf', {}, networking) |
346 | |
347 | |
348 | @@ -215,7 +226,7 @@ |
349 | 'The current user is used if this script is not run as ' |
350 | 'root and this argument is omitted.') |
351 | parser.add_argument( |
352 | - '-e', '--email', |
353 | + '-E', '--email', |
354 | help='The email of the user, used for bzr whoami. This argument ' |
355 | 'can be omitted if a bzr id exists for current user.') |
356 | parser.add_argument( |
357 | |
358 | === modified file 'lpsetup/subcommands/initlxc.py' |
359 | --- lpsetup/subcommands/initlxc.py 2012-07-10 17:36:49 +0000 |
360 | +++ lpsetup/subcommands/initlxc.py 2012-07-12 22:14:19 +0000 |
361 | @@ -156,7 +156,7 @@ |
362 | private_key, public_key, ssh_key_name, home_dir): |
363 | """Prepare the Launchpad environment inside an LXC.""" |
364 | # Use ssh to call this script from inside the container. |
365 | - args = ['init-host', '-u', user, '-e', email, '-f', full_name, |
366 | + args = ['init-host', '-u', user, '-E', email, '-f', full_name, |
367 | '-l', lpuser, '-S', ssh_key_name, |
368 | ] |
369 | |
370 | @@ -220,10 +220,15 @@ |
371 | help='The LXC container architecture. ' |
372 | '[DEFAULT={0}]'.format(LXC_GUEST_ARCH)) |
373 | parser.add_argument( |
374 | - '-r', '--lxc-os', default=LXC_GUEST_OS, |
375 | + '-R', '--lxc-os', default=LXC_GUEST_OS, |
376 | choices=LXC_GUEST_CHOICES, |
377 | help='The LXC container distro codename. ' |
378 | '[DEFAULT={0}]'.format(LXC_GUEST_OS)) |
379 | parser.add_argument( |
380 | '--stop-lxc', action='store_true', |
381 | help='Shut down the LXC container at the end of the process.') |
382 | + parser.add_argument( |
383 | + '--install-subunit', action='store_true', |
384 | + help='Install subunit in the host machine. Activate this if you ' |
385 | + 'are using this command to create an automated parallel ' |
386 | + 'testing environment e.g. for buildbot.') |
387 | |
388 | === modified file 'lpsetup/subcommands/initrepo.py' |
389 | --- lpsetup/subcommands/initrepo.py 2012-07-10 18:11:30 +0000 |
390 | +++ lpsetup/subcommands/initrepo.py 2012-07-12 22:14:19 +0000 |
391 | @@ -2,7 +2,16 @@ |
392 | # Copyright 2012 Canonical Ltd. This software is licensed under the |
393 | # GNU Affero General Public License version 3 (see the file LICENSE). |
394 | |
395 | -"""initrepo subcommand: prepare source code destinations and download it.""" |
396 | +"""init-repo subcommand: prepare source code destinations and download them. |
397 | + |
398 | +Prepares the user's Launchpad directory structure and downloads the |
399 | +latest Launchpad source code. Sets up ~/.bazaar/locations.conf |
400 | +appropriately. The repository uses the sandbox development model as |
401 | +specified in `lxc-install`. |
402 | + |
403 | +Run as the user in the Launchpad target, either a host machine or LXC |
404 | +container. |
405 | +""" |
406 | |
407 | __metaclass__ = type |
408 | __all__ = [ |
409 | @@ -81,8 +90,8 @@ |
410 | handlers.handle_source, |
411 | ) |
412 | |
413 | - def add_arguments(self, parser): |
414 | - super(SubCommand, self).add_arguments(parser) |
415 | + @staticmethod |
416 | + def add_common_arguments(parser): |
417 | parser.add_argument( |
418 | '--source', default=None, |
419 | help='Location from which to retrieve Launchpad source. Default ' |
420 | @@ -106,3 +115,7 @@ |
421 | 'The directory must reside under the home directory of the ' |
422 | 'given user (see -u argument). ' |
423 | '[DEFAULT={0}]'.format(CHECKOUT_DIR)) |
424 | + |
425 | + def add_arguments(self, parser): |
426 | + super(SubCommand, self).add_arguments(parser) |
427 | + self.add_common_arguments(parser) |
428 | |
429 | === modified file 'lpsetup/subcommands/install_lxc.py' |
430 | --- lpsetup/subcommands/install_lxc.py 2012-07-10 19:06:12 +0000 |
431 | +++ lpsetup/subcommands/install_lxc.py 2012-07-12 22:14:19 +0000 |
432 | @@ -8,38 +8,25 @@ |
433 | __all__ = [ |
434 | 'create_scripts', |
435 | 'SubCommand', |
436 | - 'setup_lxc', |
437 | ] |
438 | |
439 | import os |
440 | -import subprocess |
441 | |
442 | -from shelltoolbox import ( |
443 | - get_su_command, |
444 | - mkdirs, |
445 | - run, |
446 | - su, |
447 | - ) |
448 | from lpsetup.handlers import ( |
449 | handle_directories, |
450 | - handle_testing, |
451 | + handle_source, |
452 | ) |
453 | from lpsetup.settings import ( |
454 | - LP_BRANCH_NAME, |
455 | - LP_HTTP_REPO, |
456 | - LP_SOURCE_DEPS, |
457 | - LP_SSH_REPO, |
458 | - CHECKOUT_DIR, |
459 | - DEPENDENCIES_DIR, |
460 | LXC_IP_COMMAND, |
461 | SCRIPTS, |
462 | ) |
463 | from lpsetup.subcommands import ( |
464 | - inithost, |
465 | + finish_inithost, |
466 | initlxc, |
467 | + initrepo, |
468 | + update, |
469 | ) |
470 | from lpsetup.utils import ( |
471 | - call, |
472 | get_file_header, |
473 | render_to_file, |
474 | sshlxc as ssh, |
475 | @@ -81,67 +68,43 @@ |
476 | f.write('0\n') |
477 | |
478 | |
479 | -def setup_lxc(lxc_name, ssh_key_path, user, dependencies_dir, repository): |
480 | - """Set up the Launchpad environment inside an LXC.""" |
481 | - # Use ssh to call this script from inside the container. |
482 | - args = [ |
483 | - 'install', '-u', user, '-s', 'setup_apt', 'setup_bzr_locatoins', |
484 | - 'setup_launchpad', '-d', dependencies_dir, '-r', repository, |
485 | - ] |
486 | - cmd = this_command(repository, args) |
487 | +def cmd_in_lxc(lxc_name, ssh_key_path, home_dir, args, as_user=None): |
488 | + print "args = ", args |
489 | + cmd = this_command(home_dir, args) |
490 | + if as_user is not None: |
491 | + cmd = "su {} -c '{}'".format(as_user, cmd) |
492 | + print "CMD = ", cmd |
493 | ssh(lxc_name, cmd, key=ssh_key_path) |
494 | |
495 | |
496 | -def setup_codebase(user, checkout_dir, dependencies_dir, valid_ssh_keys=True): |
497 | - """Set up Launchpad repository and source dependencies. |
498 | - |
499 | - Return True if new changes are pulled from bzr repository. |
500 | - """ |
501 | - # TODO If doing no trees, use --lightweight. |
502 | - # Using real su because bzr uses uid. |
503 | - if os.path.exists(checkout_dir): |
504 | - # Pull the repository. |
505 | - revno_args = ('bzr', 'revno', checkout_dir) |
506 | - revno = run(*revno_args) |
507 | - call(*get_su_command(user, ['bzr', 'pull', '-d', checkout_dir])) |
508 | - changed = revno != run(*revno_args) |
509 | - else: |
510 | - # Branch the repository. |
511 | - # If we have valid SSH keys we should use the "lp:" style URL, "http" |
512 | - # if not. |
513 | - if valid_ssh_keys: |
514 | - repo = LP_SSH_REPO |
515 | - else: |
516 | - repo = LP_HTTP_REPO |
517 | - cmd = ('bzr', 'branch', repo, checkout_dir) |
518 | - call(*get_su_command(user, cmd)) |
519 | - changed = True |
520 | - # Check repository integrity. |
521 | - if subprocess.call(['bzr', 'status', '-q', checkout_dir]): |
522 | - raise subprocess.CalledProcessError( |
523 | - 'Repository {0} is corrupted.'.format(checkout_dir)) |
524 | - # Set up source dependencies. |
525 | - with su(user): |
526 | - for subdir in ('eggs', 'yui', 'sourcecode'): |
527 | - mkdirs(os.path.join(dependencies_dir, subdir)) |
528 | - download_cache = os.path.join(dependencies_dir, 'download-cache') |
529 | - if os.path.exists(download_cache): |
530 | - call('bzr', 'up', download_cache) |
531 | - else: |
532 | - call('bzr', 'co', '--lightweight', LP_SOURCE_DEPS, download_cache) |
533 | - return changed |
534 | - |
535 | - |
536 | -def fetch(user, repository, dependencies_dir, valid_ssh_keys): |
537 | - """Create a repo for the Launchpad code and retrieve it.""" |
538 | - # TODO Add --no-trees handling. |
539 | - with su(user): |
540 | - # Set up the repository. |
541 | - mkdirs(repository) |
542 | - call('bzr', 'init-repo', repository) |
543 | - # Set up the codebase. |
544 | - checkout_dir = os.path.join(repository, LP_BRANCH_NAME) |
545 | - setup_codebase(user, checkout_dir, dependencies_dir, valid_ssh_keys) |
546 | +def init_repo_in_lxc(lxc_name, ssh_key_path, home_dir, user, source, |
547 | + use_http, branch_name, checkout_name, repository): |
548 | + args = [ |
549 | + 'init-repo', '--source', source, |
550 | + '--branch-name', branch_name, '--checkout-name', checkout_name, |
551 | + '--repository', repository, |
552 | + ] |
553 | + if use_http: |
554 | + args.append('--use-http') |
555 | + cmd_in_lxc(lxc_name, ssh_key_path, home_dir, args, as_user=user) |
556 | + |
557 | + |
558 | +def update_in_lxc(lxc_name, ssh_key_path, home_dir, user, external_path, |
559 | + use_http, checkout_name, repository): |
560 | + working_dir = os.path.join(repository, checkout_name) |
561 | + args = [ |
562 | + 'update', '--external-path', external_path, '-W', working_dir, |
563 | + ] |
564 | + if use_http: |
565 | + args.append('--use-http') |
566 | + cmd_in_lxc(lxc_name, ssh_key_path, home_dir, args, as_user=user) |
567 | + |
568 | + |
569 | +def finish_inithost_in_lxc(lxc_name, ssh_key_path, home_dir, user, code_dir): |
570 | + args = [ |
571 | + 'finish-init-host', '--user', user, '--code-dir', code_dir, |
572 | + ] |
573 | + cmd_in_lxc(lxc_name, ssh_key_path, home_dir, args) |
574 | |
575 | |
576 | class SubCommand(initlxc.SubCommand): |
577 | @@ -149,29 +112,23 @@ |
578 | development model. |
579 | """ |
580 | |
581 | - fetch_step = (fetch, |
582 | - 'user', 'repository', 'dependencies_dir', 'valid_ssh_keys') |
583 | - |
584 | - steps = ( |
585 | - inithost.SubCommand.initialize_step, |
586 | - fetch_step, |
587 | - (create_scripts, |
588 | - 'lxc_name', 'ssh_key_path', 'user'), |
589 | - initlxc.SubCommand.create_lxc_step + ('install_subunit',), |
590 | - initlxc.SubCommand.start_lxc_step, |
591 | - initlxc.SubCommand.wait_for_lxc_step, |
592 | - # XXX bac, the following step no longer exists. The functionality for |
593 | - # this step needs to be refactored or removed. |
594 | - # initlxc.SubCommand.initialize_lxc_step, |
595 | - (setup_lxc, |
596 | - 'lxc_name', 'ssh_key_path', 'user', 'dependencies_dir', 'repository'), |
597 | - initlxc.SubCommand.stop_lxc_step, |
598 | + steps = initlxc.SubCommand.steps + ( |
599 | + # Run on host: |
600 | + (create_scripts, 'lxc_name', 'ssh_key_path', 'user'), |
601 | + # Run inside the container: |
602 | + (init_repo_in_lxc, 'lxc_name', 'ssh_key_path', 'home_dir', 'user', |
603 | + 'source', 'use_http', 'branch_name', 'checkout_name', 'repository'), |
604 | + (update_in_lxc, 'lxc_name', 'ssh_key_path', 'home_dir', 'user', |
605 | + 'external_path', 'use_http', 'checkout_name', 'repository'), |
606 | + (finish_inithost_in_lxc, 'lxc_name', 'ssh_key_path', 'home_dir', |
607 | + 'user', 'code_dir'), |
608 | ) |
609 | + |
610 | help = __doc__ |
611 | |
612 | def get_handlers(self, namespace): |
613 | handlers = super(SubCommand, self).get_handlers(namespace) |
614 | - return handlers + (handle_directories, handle_testing) |
615 | + return handlers + (handle_directories, handle_source) |
616 | |
617 | def call_create_scripts(self, namespace, step, args): |
618 | """Run the `create_scripts` step only if the related flag is set.""" |
619 | @@ -180,30 +137,11 @@ |
620 | |
621 | def add_arguments(self, parser): |
622 | super(SubCommand, self).add_arguments(parser) |
623 | - parser.add_argument( |
624 | - '-d', '--dependencies-dir', default=DEPENDENCIES_DIR, |
625 | - help='The directory of the Launchpad dependencies to be created. ' |
626 | - 'The directory must reside under the home directory of the ' |
627 | - 'given user (see -u argument). ' |
628 | - '[DEFAULT={0}]'.format(DEPENDENCIES_DIR)) |
629 | - parser.add_argument( |
630 | - '-c', '--repository', default=CHECKOUT_DIR, |
631 | - help='The directory of the Launchpad repository to be created. ' |
632 | - 'The directory must reside under the home directory of the ' |
633 | - 'given user (see -u argument). ' |
634 | - '[DEFAULT={0}]'.format(CHECKOUT_DIR)) |
635 | + # Inherit arguments from subcommands we depend upon. |
636 | + initrepo.SubCommand.add_common_arguments(parser) |
637 | + update.SubCommand.add_common_arguments(parser) |
638 | + finish_inithost.SubCommand.add_common_arguments(parser) |
639 | # Add parallel testing related arguments. |
640 | parser.add_argument( |
641 | '-C', '--create-scripts', action='store_true', |
642 | help='Create the scripts used by buildbot for parallel testing.') |
643 | - # The following flag is not present in the inithost sub command since |
644 | - # subunit is always installed there as a dependency of |
645 | - # launchpad-developer-dependencies. |
646 | - parser.add_argument( |
647 | - '--install-subunit', action='store_true', |
648 | - help='Install subunit in the host machine. Activate this if you ' |
649 | - 'are using this command to create an automated parallel ' |
650 | - 'testing environment e.g. for buildbot.') |
651 | - parser.add_argument( |
652 | - '--testing', action='store_true', |
653 | - help='Same as --feed-random --create-scripts --install-subunit.') |
654 | |
655 | === modified file 'lpsetup/subcommands/update.py' |
656 | --- lpsetup/subcommands/update.py 2012-07-10 17:25:09 +0000 |
657 | +++ lpsetup/subcommands/update.py 2012-07-12 22:14:19 +0000 |
658 | @@ -18,7 +18,10 @@ |
659 | |
660 | from lpsetup import argparser |
661 | from lpsetup import handlers |
662 | -from lpsetup.settings import LP_SOURCE_DEPS |
663 | +from lpsetup.settings import ( |
664 | + LP_CODE_DIR, |
665 | + LP_SOURCE_DEPS, |
666 | + ) |
667 | |
668 | |
669 | def initialize_directories(external_path): |
670 | @@ -38,7 +41,7 @@ |
671 | run(cmd, use_http_param, source_path) |
672 | |
673 | # Update the download cache. |
674 | - download_cache = os.path.join(external_path, 'download-cache') |
675 | + download_cache = os.path.join(working_dir, 'download-cache') |
676 | if os.path.exists(download_cache): |
677 | run('bzr', 'up', download_cache) |
678 | else: |
679 | @@ -77,20 +80,21 @@ |
680 | handlers.handle_working_dir, |
681 | ) |
682 | |
683 | + @staticmethod |
684 | + def add_common_arguments(parser): |
685 | + parser.add_argument( |
686 | + '-e', '--external-path', default='.', |
687 | + help='Path to directory that contains sourcecode ' |
688 | + 'and download-cache directories.') |
689 | + |
690 | def add_arguments(self, parser): |
691 | super(SubCommand, self).add_arguments(parser) |
692 | - parser.add_argument( |
693 | - '-e', '--external-path', default='.', |
694 | - help='Path to directory that contains sourcecode ' |
695 | - 'and download-cache directories.' |
696 | - ) |
697 | + self.add_common_arguments(parser) |
698 | parser.add_argument( |
699 | '--use-http', default=False, action='store_true', |
700 | help='Force bzr to use http to get the sourcecode ' |
701 | - 'branches rather than using bzr+ssh.' |
702 | - ) |
703 | + 'branches rather than using bzr+ssh.') |
704 | parser.add_argument( |
705 | - 'working_dir', default='.', |
706 | - help='Path to branch to update. Default is ' |
707 | - 'the current directory. ' |
708 | - ) |
709 | + '-W', '--working-dir', default=LP_CODE_DIR, |
710 | + help='Path to branch to update. ' |
711 | + '[DEFAULT={0}]'.format(LP_CODE_DIR)) |
712 | |
713 | === renamed file 'lpsetup/tests/subcommands/disabled_test_finish_inithost.py' => 'lpsetup/tests/subcommands/test_finish_inithost.py' (properties changed: +x to -x) |
714 | --- lpsetup/tests/subcommands/disabled_test_finish_inithost.py 2012-07-10 19:35:18 +0000 |
715 | +++ lpsetup/tests/subcommands/test_finish_inithost.py 2012-07-12 22:14:19 +0000 |
716 | @@ -2,54 +2,40 @@ |
717 | # Copyright 2012 Canonical Ltd. This software is licensed under the |
718 | # GNU Affero General Public License version 3 (see the file LICENSE). |
719 | |
720 | -"""Tests for the install sub command.""" |
721 | +"""Tests for the finish-init-host sub command.""" |
722 | |
723 | import unittest |
724 | |
725 | from lpsetup import handlers |
726 | from lpsetup.subcommands import finish_inithost |
727 | -from lpsetup.tests.subcommands import test_inithost |
728 | from lpsetup.tests.utils import ( |
729 | get_random_string, |
730 | StepsBasedSubCommandTestMixin, |
731 | ) |
732 | |
733 | |
734 | -setup_bzr_locations_step = ( |
735 | - finish_inithost.setup_bzr_locations_as_root, |
736 | - ['user', 'lpuser', 'repository']) |
737 | setup_launchpad_step = ( |
738 | - finish_inithost.setup_launchpad, ['user', 'dependencies_dir', 'repository', |
739 | - 'valid_ssh_keys']) |
740 | + finish_inithost.setup_launchpad, ['user', 'code_dir']) |
741 | |
742 | |
743 | def get_arguments(): |
744 | - inithost_arguments = test_inithost.get_arguments() |
745 | - dependencies_dir = '~/' + get_random_string() |
746 | - repository = '~/' + get_random_string() |
747 | - return inithost_arguments + ('-d', dependencies_dir, '-r', repository) |
748 | - |
749 | - |
750 | -class InstallTest(StepsBasedSubCommandTestMixin, unittest.TestCase): |
751 | + code_dir = '~/' + get_random_string() |
752 | + user = get_random_string() |
753 | + return ('-c', code_dir, '-u', user) |
754 | + |
755 | + |
756 | +class FinishInitHostTest(StepsBasedSubCommandTestMixin, unittest.TestCase): |
757 | |
758 | sub_command_class = finish_inithost.SubCommand |
759 | expected_arguments = get_arguments() |
760 | expected_handlers = ( |
761 | handlers.handle_user, |
762 | - handlers.handle_lpuser_as_username, |
763 | - handlers.handle_userdata, |
764 | - handlers.handle_ssh_keys, |
765 | handlers.handle_directories, |
766 | ) |
767 | |
768 | @property |
769 | def expected_steps(self): |
770 | - from lpsetup.tests.subcommands import test_install_lxc |
771 | return ( |
772 | - test_inithost.initialize_step, |
773 | - test_install_lxc.fetch_step, |
774 | - setup_bzr_locations_step, |
775 | - test_inithost.setup_apt_step, |
776 | setup_launchpad_step, |
777 | ) |
778 | needs_root = True |
779 | |
780 | === modified file 'lpsetup/tests/subcommands/test_inithost.py' |
781 | --- lpsetup/tests/subcommands/test_inithost.py 2012-07-11 11:47:39 +0000 |
782 | +++ lpsetup/tests/subcommands/test_inithost.py 2012-07-12 22:14:19 +0000 |
783 | @@ -36,7 +36,7 @@ |
784 | public_key = get_random_string() |
785 | ssh_key_name = get_random_string() |
786 | return ( |
787 | - '-u', user, '-e', email, '-f', full_name, '-l', lpuser, |
788 | + '-u', user, '-E', email, '-f', full_name, '-l', lpuser, |
789 | '-v', private_key, '-b', public_key, '-S', ssh_key_name) |
790 | |
791 | |
792 | |
793 | === modified file 'lpsetup/tests/subcommands/test_initlxc.py' |
794 | --- lpsetup/tests/subcommands/test_initlxc.py 2012-07-10 17:36:49 +0000 |
795 | +++ lpsetup/tests/subcommands/test_initlxc.py 2012-07-12 22:14:19 +0000 |
796 | @@ -38,11 +38,11 @@ |
797 | lxc_arch = random.choice(['i386', 'amd64']) |
798 | lxc_os = random.choice(settings.LXC_GUEST_CHOICES) |
799 | return ( |
800 | - lxc_name, '-A', lxc_arch, '-r', lxc_os, |
801 | + lxc_name, '-A', lxc_arch, '-R', lxc_os, |
802 | '--stop-lxc') + inithost_arguments |
803 | |
804 | |
805 | -class InithostTest(StepsBasedSubCommandTestMixin, unittest.TestCase): |
806 | +class InitLxcTest(StepsBasedSubCommandTestMixin, unittest.TestCase): |
807 | |
808 | sub_command_class = initlxc.SubCommand |
809 | expected_arguments = get_arguments() |
810 | |
811 | === renamed file 'lpsetup/tests/subcommands/disabled_test_install_lxc.py' => 'lpsetup/tests/subcommands/test_install_lxc.py' (properties changed: +x to -x) |
812 | --- lpsetup/tests/subcommands/disabled_test_install_lxc.py 2012-07-10 19:35:18 +0000 |
813 | +++ lpsetup/tests/subcommands/test_install_lxc.py 2012-07-12 22:14:19 +0000 |
814 | @@ -9,7 +9,6 @@ |
815 | from lpsetup import handlers |
816 | from lpsetup.subcommands import install_lxc |
817 | from lpsetup.tests.subcommands import ( |
818 | - test_inithost, |
819 | test_initlxc, |
820 | ) |
821 | from lpsetup.tests.utils import ( |
822 | @@ -18,24 +17,32 @@ |
823 | ) |
824 | |
825 | |
826 | -fetch_step = ( |
827 | - install_lxc.fetch, ['user', 'repository', 'dependencies_dir', |
828 | - 'valid_ssh_keys']) |
829 | create_scripts_step = ( |
830 | install_lxc.create_scripts, ['lxc_name', 'ssh_key_path', 'user']) |
831 | -create_lxc_callable, create_lxc_args = test_initlxc.create_lxc_step |
832 | -create_lxc_step = (create_lxc_callable, create_lxc_args + ['install_subunit']) |
833 | -setup_lxc_step = ( |
834 | - install_lxc.setup_lxc, ['lxc_name', 'ssh_key_path', 'user', |
835 | - 'dependencies_dir', 'repository']) |
836 | + |
837 | +init_repo_in_lxc_step = ( |
838 | + install_lxc.init_repo_in_lxc, [ |
839 | + 'lxc_name', 'ssh_key_path', 'home_dir', 'user', 'source', 'use_http', |
840 | + 'branch_name', 'checkout_name', 'repository', |
841 | + ]) |
842 | + |
843 | +update_in_lxc_step = ( |
844 | + install_lxc.update_in_lxc, [ |
845 | + 'lxc_name', 'ssh_key_path', 'home_dir', 'user', 'external_path', |
846 | + 'use_http', 'checkout_name', 'repository', |
847 | + ]) |
848 | + |
849 | +finish_inithost_in_lxc_step = ( |
850 | + install_lxc.finish_inithost_in_lxc, [ |
851 | + 'lxc_name', 'ssh_key_path', 'home_dir', 'user', 'code_dir', |
852 | + ]) |
853 | |
854 | |
855 | def get_arguments(): |
856 | - dependencies_dir = '~/' + get_random_string() |
857 | repository = '~/' + get_random_string() |
858 | return test_initlxc.get_arguments() + ( |
859 | - '-d', dependencies_dir, '-c', repository, |
860 | - '--create-scripts', '--install-subunit', '--testing', |
861 | + '-r', repository, |
862 | + '--create-scripts', |
863 | ) |
864 | |
865 | |
866 | @@ -43,23 +50,15 @@ |
867 | |
868 | sub_command_class = install_lxc.SubCommand |
869 | expected_arguments = get_arguments() |
870 | - expected_handlers = ( |
871 | - handlers.handle_user, |
872 | - handlers.handle_lpuser_as_username, |
873 | - handlers.handle_userdata, |
874 | - handlers.handle_ssh_keys, |
875 | + expected_handlers = test_initlxc.InitLxcTest.expected_handlers + ( |
876 | handlers.handle_directories, |
877 | - handlers.handle_testing, |
878 | + handlers.handle_source, |
879 | ) |
880 | - expected_steps = ( |
881 | - test_inithost.initialize_step, |
882 | - fetch_step, |
883 | + expected_steps = test_initlxc.InitLxcTest.expected_steps + ( |
884 | create_scripts_step, |
885 | - create_lxc_step, |
886 | - test_initlxc.start_lxc_step, |
887 | - test_initlxc.wait_for_lxc_step, |
888 | - test_initlxc.initialize_lxc_step, |
889 | - setup_lxc_step, |
890 | - test_initlxc.stop_lxc_step, |
891 | + init_repo_in_lxc_step, |
892 | + update_in_lxc_step, |
893 | + finish_inithost_in_lxc_step, |
894 | ) |
895 | needs_root = True |
896 | + maxDiff = None |
897 | |
898 | === modified file 'lpsetup/tests/subcommands/test_update.py' |
899 | --- lpsetup/tests/subcommands/test_update.py 2012-07-07 12:58:12 +0000 |
900 | +++ lpsetup/tests/subcommands/test_update.py 2012-07-12 22:14:19 +0000 |
901 | @@ -18,7 +18,8 @@ |
902 | return ( |
903 | '--external-path', get_random_string(), |
904 | '--use-http', |
905 | - get_random_string(), |
906 | + '-e', '../devel', |
907 | + '-W', '~/' + get_random_string(), |
908 | ) |
909 | |
910 | init_dir_step = (update.initialize_directories, ['external_path']) |
911 | |
912 | === modified file 'pre-commit.sh' |
913 | --- pre-commit.sh 2012-07-10 17:58:00 +0000 |
914 | +++ pre-commit.sh 2012-07-12 22:14:19 +0000 |
915 | @@ -1,4 +1,4 @@ |
916 | #!/bin/bash |
917 | |
918 | -pyfiles=`find . -name "*.py" | grep -v distribute_setup.py ` |
919 | +pyfiles=`find . -name "*.py" | grep -v distribute_setup.py` |
920 | pocketlint $pyfiles && pep8 $pyfiles && nosetests |
921 | |
922 | === modified file 'setup.cfg' |
923 | --- setup.cfg 2012-07-10 19:35:18 +0000 |
924 | +++ setup.cfg 2012-07-12 22:14:19 +0000 |
925 | @@ -1,11 +1,10 @@ |
926 | [nosetests] |
927 | detailed-errors=1 |
928 | exclude=handle_testing |
929 | -with-coverage=0 |
930 | +with-coverage=1 |
931 | cover-package=lpsetup |
932 | with-doctest=1 |
933 | -# Including ignore-files here or on the command line causes the tests |
934 | -# to fail with a complaint about the version of distribute. As a |
935 | -# work-around, rename disabled tests to 'disabled_'+test_name and set |
936 | -# the execute bit. |
937 | -#ignore-files=disabled* |
938 | +# Specifying 'where' should not be required but it is a work-around |
939 | +# for a problem presented by having 'ignore-files'. |
940 | +where=lpsetup |
941 | +ignore-files=disabled* |
A run of install-lxc is currently under test in a clean precise VM.