Merge lp:~cjwatson/launchpad-buildd/livefs into lp:launchpad-buildd
- livefs
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Colin Watson |
Approved revision: | 101 |
Merged at revision: | 98 |
Proposed branch: | lp:~cjwatson/launchpad-buildd/livefs |
Merge into: | lp:launchpad-buildd |
Diff against target: |
504 lines (+415/-4) 9 files modified
Makefile (+3/-2) buildd-slave.tac (+2/-0) buildlivefs (+167/-0) debian/changelog (+2/-0) debian/rules (+1/-1) debian/upgrade-config (+14/-1) lpbuildd/livefs.py (+105/-0) lpbuildd/tests/test_livefs.py (+118/-0) template-buildd-slave.conf (+3/-0) |
To merge this branch: | bzr merge lp:~cjwatson/launchpad-buildd/livefs |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
William Grant | code | Approve | |
Review via email: mp+193682@code.launchpad.net |
Commit message
Add a new "livefs" build manager, based on livecd-
Description of the change
This is a first cut at the build slave side of livefs building. It's somewhat based on BuildLiveCD from livecd-rootfs, but refactored into launchpad-buildd style and with a good deal of historical cruft stripped out. I've successfully tested this with an ubuntu-
livecd-rootfs notionally has eatmydata support, but I don't think I ever got that deployed and on closer inspection I'm not clear that it ever worked in livecd-rootfs (bad syntax of environment variable handling; libeatmydata.so doesn't exist in the chroot). I've omitted this for the moment, and perhaps we can restore it later.
Note that if you're testing this in an LXC container then you need to use "aa-complain /usr/bin/
Colin Watson (cjwatson) wrote : | # |
- 98. By Colin Watson
-
Prepend linux32 to chroot commands on powerpc (from BuildLiveCD).
- 99. By Colin Watson
-
Pass datestamp as an option rather than unreliably computing it in buildlivefs.
- 100. By Colin Watson
-
Fail the builder if buildlivefs returns an unrecognised exit code.
- 101. By Colin Watson
-
Sort tests.
Colin Watson (cjwatson) wrote : | # |
I think this is actually ready now.
William Grant (wgrant) wrote : | # |
127 + def build(self):
128 + if self.options.locale is not None:
The locale and non-locale cases seem to be almost entirely divergent. Do we really need both?
365 + def gatherResults(
366 + """Gather the results of the build and add them to the file cache."""
367 + for entry in sorted(
368 + if entry.startswit
369 + self._slave.
370 + os.path.
There's no manifest-like file from which we can parse the build result filenames?
Colin Watson (cjwatson) wrote : | # |
On Tue, Nov 26, 2013 at 02:44:16AM -0000, William Grant wrote:
> 127 + def build(self):
> 128 + if self.options.locale is not None:
>
> The locale and non-locale cases seem to be almost entirely divergent. Do we really need both?
For the time being, yes, because the Chinese Edition was still built by
Canonical in precise. That's been superseded by UbuntuKylin now, so
we'll probably be able to get rid of this once we no longer care about
building images for precise (assuming nobody wants us to do a similar
thing again), but not quite yet.
> 365 + def gatherResults(
> 366 + """Gather the results of the build and add them to the file cache."""
> 367 + for entry in sorted(
> 368 + if entry.startswit
> 369 + self._slave.
> 370 + os.path.
>
> There's no manifest-like file from which we can parse the build result filenames?
Not right now. Do you think that's a problem? If so I'll need to do
some work in livecd-rootfs to set one up.
Perhaps it would be sufficient to just make doubly sure that the build
directory is empty before we start a build? At the moment it looks like
the old system (livecd-
having cleaned things out, and come to think of it I'm not too sure that
I even preserved that in this launchpad-buildd version, so I'll need to
do something there.
Colin Watson (cjwatson) wrote : | # |
Oh, actually, I clean out the build directory at the start of each build:
def initiate(self, files, chroot, extra_args):
"""Initiate a build with a given set of files and chroot."""
if os.path.
So this should be fine.
Preview Diff
1 | === modified file 'Makefile' |
2 | --- Makefile 2013-10-03 10:39:23 +0000 |
3 | +++ Makefile 2013-11-04 11:22:27 +0000 |
4 | @@ -31,5 +31,6 @@ |
5 | lpbuildd.tests.test_buildd_slave \ |
6 | lpbuildd.tests.test_check_implicit_pointer_functions \ |
7 | lpbuildd.tests.test_harness \ |
8 | - lpbuildd.tests.test_translationtemplatesbuildmanager \ |
9 | - lpbuildd.tests.test_sourcepackagerecipe |
10 | + lpbuildd.tests.test_livefs \ |
11 | + lpbuildd.tests.test_sourcepackagerecipe \ |
12 | + lpbuildd.tests.test_translationtemplatesbuildmanager |
13 | |
14 | === modified file 'buildd-slave.tac' |
15 | --- buildd-slave.tac 2011-11-09 08:50:17 +0000 |
16 | +++ buildd-slave.tac 2013-11-04 11:22:27 +0000 |
17 | @@ -8,6 +8,7 @@ |
18 | from twisted.application import service, strports |
19 | from lpbuildd.slave import XMLRPCBuildDSlave |
20 | from lpbuildd.binarypackage import BinaryPackageBuildManager |
21 | +from lpbuildd.livefs import LiveFilesystemBuildManager |
22 | from lpbuildd.sourcepackagerecipe import ( |
23 | SourcePackageRecipeBuildManager) |
24 | from lpbuildd.translationtemplates import ( |
25 | @@ -30,6 +31,7 @@ |
26 | slave.registerBuilder(SourcePackageRecipeBuildManager, "sourcepackagerecipe") |
27 | slave.registerBuilder( |
28 | TranslationTemplatesBuildManager, 'translation-templates') |
29 | +slave.registerBuilder(LiveFilesystemBuildManager, "livefs") |
30 | |
31 | application = service.Application('BuildDSlave') |
32 | builddslaveService = service.IServiceCollection(application) |
33 | |
34 | === added file 'buildlivefs' |
35 | --- buildlivefs 1970-01-01 00:00:00 +0000 |
36 | +++ buildlivefs 2013-11-04 11:22:27 +0000 |
37 | @@ -0,0 +1,167 @@ |
38 | +#! /usr/bin/python -u |
39 | +# Copyright 2013 Canonical Ltd. This software is licensed under the |
40 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
41 | + |
42 | +"""A script that builds a live file system.""" |
43 | + |
44 | +__metaclass__ = type |
45 | + |
46 | +from optparse import OptionParser |
47 | +import os |
48 | +import re |
49 | +import subprocess |
50 | +import sys |
51 | +import traceback |
52 | + |
53 | + |
54 | +RETCODE_SUCCESS = 0 |
55 | +RETCODE_FAILURE_INSTALL = 200 |
56 | +RETCODE_FAILURE_BUILD = 201 |
57 | + |
58 | + |
59 | +def get_build_path(build_id, *extra): |
60 | + """Generate a path within the build directory. |
61 | + |
62 | + :param build_id: the build id to use. |
63 | + :param extra: the extra path segments within the build directory. |
64 | + :return: the generated path. |
65 | + """ |
66 | + return os.path.join(os.environ["HOME"], "build-" + build_id, *extra) |
67 | + |
68 | + |
69 | +non_meta_re = re.compile(r'^[a-zA-Z0-9+,./:=@_-]+$') |
70 | + |
71 | +def shell_escape(arg): |
72 | + if non_meta_re.match(arg): |
73 | + return arg |
74 | + else: |
75 | + return "'%s'" % arg.replace("'", "'\\''") |
76 | + |
77 | + |
78 | +class LiveFSBuilder: |
79 | + """Builds a live file system.""" |
80 | + |
81 | + def __init__(self, options): |
82 | + self.options = options |
83 | + self.chroot_path = get_build_path( |
84 | + self.options.build_id, 'chroot-autobuild') |
85 | + |
86 | + def chroot(self, args, echo=False): |
87 | + """Run a command in the chroot. |
88 | + |
89 | + :param args: the command and arguments to run. |
90 | + """ |
91 | + if self.options.arch == "powerpc": |
92 | + args = ["linux32"] + args |
93 | + if echo: |
94 | + print "Running in chroot: %s" % ' '.join( |
95 | + "'%s'" % arg for arg in args) |
96 | + sys.stdout.flush() |
97 | + subprocess.check_call([ |
98 | + "/usr/bin/sudo", "/usr/sbin/chroot", self.chroot_path] + args) |
99 | + |
100 | + def run_build_command(self, args, env=None, echo=False): |
101 | + """Run a build command in the chroot. |
102 | + |
103 | + This is unpleasant because we need to run it in /build under sudo |
104 | + chroot, and there's no way to do this without either a helper |
105 | + program in the chroot or unpleasant quoting. We go for the |
106 | + unpleasant quoting. |
107 | + |
108 | + :param args: the command and arguments to run. |
109 | + :param env: dictionary of additional environment variables to set. |
110 | + """ |
111 | + args = [shell_escape(arg) for arg in args] |
112 | + if env: |
113 | + args = ["env"] + [ |
114 | + "%s=%s" % (key, shell_escape(value)) |
115 | + for key, value in env.items()] + args |
116 | + command = "cd /build && %s" % " ".join(args) |
117 | + self.chroot(["/bin/sh", "-c", command], echo=echo) |
118 | + |
119 | + def install(self): |
120 | + self.chroot(["apt-get", "-y", "install", "livecd-rootfs"]) |
121 | + if self.options.locale is not None: |
122 | + self.chroot([ |
123 | + "apt-get", "-y", "--install-recommends", "install", |
124 | + "ubuntu-defaults-builder", |
125 | + ]) |
126 | + |
127 | + def build(self): |
128 | + if self.options.locale is not None: |
129 | + self.run_build_command([ |
130 | + "ubuntu-defaults-image", |
131 | + "--locale", self.options.locale, |
132 | + "--arch", self.options.arch, |
133 | + "--release", self.options.suite, |
134 | + ]) |
135 | + else: |
136 | + self.run_build_command(["rm", "-rf", "auto"]) |
137 | + self.run_build_command(["mkdir", "-p", "auto"]) |
138 | + for lb_script in ("config", "build", "clean"): |
139 | + lb_script_path = os.path.join( |
140 | + "/usr/share/livecd-rootfs/live-build/auto", lb_script) |
141 | + self.run_build_command(["ln", "-s", lb_script_path, "auto/"]) |
142 | + self.run_build_command(["lb", "clean", "--purge"]) |
143 | + |
144 | + base_lb_env = { |
145 | + "PROJECT": self.options.project, |
146 | + "ARCH": self.options.arch, |
147 | + } |
148 | + if self.options.subproject is not None: |
149 | + base_lb_env["SUBPROJECT"] = self.options.subproject |
150 | + if self.options.subarch is not None: |
151 | + base_lb_env["SUBARCH"] = self.options.subarch |
152 | + lb_env = dict(base_lb_env) |
153 | + lb_env["SUITE"] = self.options.suite |
154 | + if self.options.datestamp is not None: |
155 | + lb_env["NOW"] = self.options.datestamp |
156 | + if self.options.image_format is not None: |
157 | + lb_env["IMAGEFORMAT"] = self.options.image_format |
158 | + if self.options.proposed: |
159 | + lb_env["PROPOSED"] = "1" |
160 | + self.run_build_command(["lb", "config"], env=lb_env) |
161 | + self.run_build_command(["lb", "build"], env=base_lb_env) |
162 | + |
163 | + |
164 | +def main(): |
165 | + parser = OptionParser() |
166 | + parser.add_option("--build-id", help="build identifier") |
167 | + parser.add_option( |
168 | + "--arch", metavar="ARCH", help="build for architecture ARCH") |
169 | + parser.add_option( |
170 | + "--subarch", metavar="SUBARCH", |
171 | + help="build for subarchitecture SUBARCH") |
172 | + parser.add_option( |
173 | + "--project", metavar="PROJECT", help="build for project PROJECT") |
174 | + parser.add_option( |
175 | + "--subproject", metavar="SUBPROJECT", |
176 | + help="build for subproject SUBPROJECT") |
177 | + parser.add_option("--suite", metavar="SUITE", help="build for suite SUITE") |
178 | + parser.add_option("--datestamp", help="date stamp") |
179 | + parser.add_option( |
180 | + "--image-format", metavar="FORMAT", help="produce an image in FORMAT") |
181 | + parser.add_option( |
182 | + "--proposed", default=False, action="store_true", |
183 | + help="enable use of -proposed pocket") |
184 | + parser.add_option( |
185 | + "--locale", metavar="LOCALE", |
186 | + help="use ubuntu-defaults-image to build an image for LOCALE") |
187 | + options, _ = parser.parse_args() |
188 | + |
189 | + builder = LiveFSBuilder(options) |
190 | + try: |
191 | + builder.install() |
192 | + except Exception: |
193 | + traceback.print_exc() |
194 | + return RETCODE_FAILURE_INSTALL |
195 | + try: |
196 | + builder.build() |
197 | + except Exception: |
198 | + traceback.print_exc() |
199 | + return RETCODE_FAILURE_BUILD |
200 | + return RETCODE_SUCCESS |
201 | + |
202 | + |
203 | +if __name__ == "__main__": |
204 | + sys.exit(main()) |
205 | |
206 | === modified file 'debian/changelog' |
207 | --- debian/changelog 2013-10-18 13:08:29 +0000 |
208 | +++ debian/changelog 2013-11-04 11:22:27 +0000 |
209 | @@ -4,6 +4,8 @@ |
210 | of other environment variables too (including DISPLAY and TERM), in line |
211 | with Debian buildds. |
212 | * Make the status XML-RPC method a synonym for status_dict. |
213 | + * Add a new "livefs" build manager, based on livecd-rootfs/BuildLiveCD |
214 | + (LP: #1247461). |
215 | |
216 | -- Colin Watson <cjwatson@ubuntu.com> Fri, 18 Oct 2013 12:24:00 +0100 |
217 | |
218 | |
219 | === modified file 'debian/rules' |
220 | --- debian/rules 2013-10-03 10:57:53 +0000 |
221 | +++ debian/rules 2013-11-04 11:22:27 +0000 |
222 | @@ -18,7 +18,7 @@ |
223 | |
224 | slavebins = unpack-chroot mount-chroot update-debian-chroot sbuild-package \ |
225 | scan-for-processes umount-chroot remove-build override-sources-list \ |
226 | - buildrecipe generate-translation-templates slave-prep |
227 | + buildrecipe generate-translation-templates slave-prep buildlivefs |
228 | |
229 | BUILDDUID=65500 |
230 | BUILDDGID=65500 |
231 | |
232 | === modified file 'debian/upgrade-config' |
233 | --- debian/upgrade-config 2013-07-29 17:37:43 +0000 |
234 | +++ debian/upgrade-config 2013-11-04 11:22:27 +0000 |
235 | @@ -130,6 +130,18 @@ |
236 | in_file.close() |
237 | out_file.close() |
238 | |
239 | +def upgrade_to_120(): |
240 | + print "Upgrading %s to version 120" % conf_file |
241 | + subprocess.call(["mv", conf_file, conf_file+"-prev115~"]) |
242 | + in_file = open(conf_file+"-prev120~", "r") |
243 | + out_file = open(conf_file, "w") |
244 | + out_file.write(in_file.read()) |
245 | + out_file.write( |
246 | + "\n[livefilesystemmanager]\n" |
247 | + "buildlivefspath = /usr/share/launchpad-buildd/slavebin/buildlivefs\n") |
248 | + in_file.close() |
249 | + out_file.close() |
250 | + |
251 | if __name__ == "__main__": |
252 | old_version = re.sub(r'[~-].*', '', old_version) |
253 | if int(old_version) < 12: |
254 | @@ -150,4 +162,5 @@ |
255 | upgrade_to_110() |
256 | if int(old_version) < 115: |
257 | upgrade_to_115() |
258 | - |
259 | + if int(old_version) < 120: |
260 | + upgrade_to_120() |
261 | |
262 | === added file 'lpbuildd/livefs.py' |
263 | --- lpbuildd/livefs.py 1970-01-01 00:00:00 +0000 |
264 | +++ lpbuildd/livefs.py 2013-11-04 11:22:27 +0000 |
265 | @@ -0,0 +1,105 @@ |
266 | +# Copyright 2013 Canonical Ltd. This software is licensed under the |
267 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
268 | + |
269 | +__metaclass__ = type |
270 | + |
271 | +import os |
272 | +import shutil |
273 | + |
274 | +from lpbuildd.debian import ( |
275 | + DebianBuildManager, |
276 | + DebianBuildState, |
277 | + get_build_path, |
278 | + ) |
279 | + |
280 | + |
281 | +RETCODE_SUCCESS = 0 |
282 | +RETCODE_FAILURE_INSTALL = 200 |
283 | +RETCODE_FAILURE_BUILD = 201 |
284 | + |
285 | + |
286 | +class LiveFilesystemBuildState(DebianBuildState): |
287 | + BUILD_LIVEFS = "BUILD_LIVEFS" |
288 | + |
289 | + |
290 | +class LiveFilesystemBuildManager(DebianBuildManager): |
291 | + """Build a live filesystem.""" |
292 | + |
293 | + initial_build_state = LiveFilesystemBuildState.BUILD_LIVEFS |
294 | + |
295 | + def __init__(self, slave, buildid, **kwargs): |
296 | + DebianBuildManager.__init__(self, slave, buildid, **kwargs) |
297 | + self.build_livefs_path = slave._config.get( |
298 | + "livefilesystemmanager", "buildlivefspath") |
299 | + |
300 | + def initiate(self, files, chroot, extra_args): |
301 | + """Initiate a build with a given set of files and chroot.""" |
302 | + self.build_path = get_build_path( |
303 | + self.home, self._buildid, "chroot-autobuild", "build") |
304 | + if os.path.isdir(self.build_path): |
305 | + shutil.rmtree(self.build_path) |
306 | + |
307 | + self.subarch = extra_args.get("subarch") |
308 | + self.project = extra_args["project"] |
309 | + self.subproject = extra_args.get("subproject") |
310 | + self.suite = extra_args["suite"] |
311 | + self.datestamp = extra_args.get("datestamp") |
312 | + self.image_format = extra_args.get("image_format") |
313 | + self.proposed = extra_args.get("proposed", False) |
314 | + self.locale = extra_args.get("locale") |
315 | + |
316 | + super(LiveFilesystemBuildManager, self).initiate( |
317 | + files, chroot, extra_args) |
318 | + |
319 | + def doRunBuild(self): |
320 | + """Run the process to build the live filesystem.""" |
321 | + args = [ |
322 | + "buildlivefs", |
323 | + "--build-id", self._buildid, |
324 | + "--arch", self.arch_tag, |
325 | + ] |
326 | + if self.subarch: |
327 | + args.extend(["--subarch", self.subarch]) |
328 | + args.extend(["--project", self.project]) |
329 | + if self.subproject: |
330 | + args.extend(["--subproject", self.subproject]) |
331 | + args.extend(["--suite", self.suite]) |
332 | + if self.datestamp: |
333 | + args.extend(["--datestamp", self.datestamp]) |
334 | + if self.image_format: |
335 | + args.extend(["--image-format", self.image_format]) |
336 | + if self.proposed: |
337 | + args.append("--proposed") |
338 | + if self.locale: |
339 | + args.extend(["--locale", self.locale]) |
340 | + self.runSubProcess(self.build_livefs_path, args) |
341 | + |
342 | + def iterate_BUILD_LIVEFS(self, retcode): |
343 | + """Finished building the live filesystem.""" |
344 | + if retcode == RETCODE_SUCCESS: |
345 | + self.gatherResults() |
346 | + print("Returning build status: OK") |
347 | + elif (retcode >= RETCODE_FAILURE_INSTALL and |
348 | + retcode <= RETCODE_FAILURE_BUILD): |
349 | + if not self.alreadyfailed: |
350 | + self._slave.buildFail() |
351 | + print("Returning build status: Build failed.") |
352 | + self.alreadyfailed = True |
353 | + else: |
354 | + if not self.alreadyfailed: |
355 | + self._slave.builderFail() |
356 | + print("Returning build status: Builder failed.") |
357 | + self.alreadyfailed = True |
358 | + self.doReapProcesses(self._state) |
359 | + |
360 | + def iterateReap_BUILD_LIVEFS(self, retcode): |
361 | + """Finished reaping after building the live filesystem.""" |
362 | + self._state = DebianBuildState.UMOUNT |
363 | + self.doUnmounting() |
364 | + |
365 | + def gatherResults(self): |
366 | + """Gather the results of the build and add them to the file cache.""" |
367 | + for entry in sorted(os.listdir(self.build_path)): |
368 | + if entry.startswith("livecd."): |
369 | + self._slave.addWaitingFile( |
370 | + os.path.join(self.build_path, entry)) |
371 | |
372 | === added file 'lpbuildd/tests/test_livefs.py' |
373 | --- lpbuildd/tests/test_livefs.py 1970-01-01 00:00:00 +0000 |
374 | +++ lpbuildd/tests/test_livefs.py 2013-11-04 11:22:27 +0000 |
375 | @@ -0,0 +1,118 @@ |
376 | +# Copyright 2013 Canonical Ltd. This software is licensed under the |
377 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
378 | + |
379 | +__metaclass__ = type |
380 | + |
381 | +import os |
382 | +import shutil |
383 | +import tempfile |
384 | + |
385 | +from testtools import TestCase |
386 | + |
387 | +from lpbuildd.livefs import ( |
388 | + LiveFilesystemBuildManager, |
389 | + LiveFilesystemBuildState, |
390 | + ) |
391 | +from lpbuildd.tests.fakeslave import FakeSlave |
392 | + |
393 | + |
394 | +class MockBuildManager(LiveFilesystemBuildManager): |
395 | + def __init__(self, *args, **kwargs): |
396 | + super(MockBuildManager, self).__init__(*args, **kwargs) |
397 | + self.commands = [] |
398 | + self.iterators = [] |
399 | + |
400 | + def runSubProcess(self, path, command, iterate=None): |
401 | + self.commands.append([path] + command) |
402 | + if iterate is None: |
403 | + iterate = self.iterate |
404 | + self.iterators.append(iterate) |
405 | + return 0 |
406 | + |
407 | + |
408 | +class TestLiveFilesystemBuildManagerIteration(TestCase): |
409 | + """Run LiveFilesystemBuildManager through its iteration steps.""" |
410 | + def setUp(self): |
411 | + super(TestLiveFilesystemBuildManagerIteration, self).setUp() |
412 | + self.working_dir = tempfile.mkdtemp() |
413 | + self.addCleanup(lambda: shutil.rmtree(self.working_dir)) |
414 | + slave_dir = os.path.join(self.working_dir, "slave") |
415 | + home_dir = os.path.join(self.working_dir, "home") |
416 | + for dir in (slave_dir, home_dir): |
417 | + os.mkdir(dir) |
418 | + self.slave = FakeSlave(slave_dir) |
419 | + self.buildid = "123" |
420 | + self.buildmanager = MockBuildManager(self.slave, self.buildid) |
421 | + self.buildmanager.home = home_dir |
422 | + self.buildmanager._cachepath = self.slave._cachepath |
423 | + self.build_dir = os.path.join( |
424 | + home_dir, "build-%s" % self.buildid, "chroot-autobuild", "build") |
425 | + |
426 | + def getState(self): |
427 | + """Retrieve build manager's state.""" |
428 | + return self.buildmanager._state |
429 | + |
430 | + def startBuild(self): |
431 | + # The build manager's iterate() kicks off the consecutive states |
432 | + # after INIT. |
433 | + extra_args = { |
434 | + "project": "ubuntu", |
435 | + "suite": "saucy", |
436 | + "arch_tag": "i386", |
437 | + } |
438 | + self.buildmanager.initiate({}, "chroot.tar.gz", extra_args) |
439 | + |
440 | + # Skip states that are done in DebianBuildManager to the state |
441 | + # directly before BUILD_LIVEFS. |
442 | + self.buildmanager._state = LiveFilesystemBuildState.UPDATE |
443 | + |
444 | + # BUILD_LIVEFS: Run the slave's payload to build the live filesystem. |
445 | + self.buildmanager.iterate(0) |
446 | + self.assertEqual( |
447 | + LiveFilesystemBuildState.BUILD_LIVEFS, self.getState()) |
448 | + expected_command = [ |
449 | + "buildlivefspath", "buildlivefs", "--build-id", self.buildid, |
450 | + "--arch", "i386", "--project", "ubuntu", "--suite", "saucy", |
451 | + ] |
452 | + self.assertEqual(expected_command, self.buildmanager.commands[-1]) |
453 | + self.assertEqual( |
454 | + self.buildmanager.iterate, self.buildmanager.iterators[-1]) |
455 | + self.assertFalse(self.slave.wasCalled("chrootFail")) |
456 | + |
457 | + def test_iterate(self): |
458 | + # The build manager iterates a normal build from start to finish. |
459 | + self.startBuild() |
460 | + |
461 | + log_path = os.path.join(self.buildmanager._cachepath, "buildlog") |
462 | + log = open(log_path, "w") |
463 | + log.write("I am a build log.") |
464 | + log.close() |
465 | + |
466 | + os.makedirs(self.build_dir) |
467 | + manifest_path = os.path.join(self.build_dir, "livecd.ubuntu.manifest") |
468 | + manifest = open(manifest_path, "w") |
469 | + manifest.write("I am a manifest file.") |
470 | + manifest.close() |
471 | + |
472 | + # After building the package, reap processes. |
473 | + self.buildmanager.iterate(0) |
474 | + expected_command = [ |
475 | + "processscanpath", "scan-for-processes", self.buildid, |
476 | + ] |
477 | + self.assertEqual( |
478 | + LiveFilesystemBuildState.BUILD_LIVEFS, self.getState()) |
479 | + self.assertEqual(expected_command, self.buildmanager.commands[-1]) |
480 | + self.assertNotEqual( |
481 | + self.buildmanager.iterate, self.buildmanager.iterators[-1]) |
482 | + self.assertFalse(self.slave.wasCalled("buildFail")) |
483 | + self.assertEqual( |
484 | + [((manifest_path,), {})], self.slave.addWaitingFile.calls) |
485 | + |
486 | + # Control returns to the DebianBuildManager in the UMOUNT state. |
487 | + self.buildmanager.iterateReap(self.getState(), 0) |
488 | + expected_command = ["umountpath", "umount-chroot", self.buildid] |
489 | + self.assertEqual(LiveFilesystemBuildState.UMOUNT, self.getState()) |
490 | + self.assertEqual(expected_command, self.buildmanager.commands[-1]) |
491 | + self.assertEqual( |
492 | + self.buildmanager.iterate, self.buildmanager.iterators[-1]) |
493 | + self.assertFalse(self.slave.wasCalled("buildFail")) |
494 | |
495 | === modified file 'template-buildd-slave.conf' |
496 | --- template-buildd-slave.conf 2013-07-24 10:42:05 +0000 |
497 | +++ template-buildd-slave.conf 2013-11-04 11:22:27 +0000 |
498 | @@ -31,3 +31,6 @@ |
499 | [translationtemplatesmanager] |
500 | generatepath = /usr/share/launchpad-buildd/slavebin/generate-translation-templates |
501 | resultarchive = translation-templates.tar.gz |
502 | + |
503 | +[livefilesystemmanager] |
504 | +buildlivefspath = /usr/share/launchpad-buildd/slavebin/buildlivefs |
One thing I know needs to be fixed: NOW can't be calculated entirely by the slave because the slave won't know whether there've been previous builds on the same day. This needs to be passed down from the manager.