Merge lp:~jml/launchpad/behavior-refactor into lp:launchpad

Proposed by Jonathan Lange
Status: Merged
Approved by: Jonathan Lange
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~jml/launchpad/behavior-refactor
Merge into: lp:launchpad
Diff against target: 723 lines (+172/-143)
11 files modified
lib/canonical/cachedproperty.py (+1/-0)
lib/lp/buildmaster/interfaces/buildfarmjobbehavior.py (+7/-8)
lib/lp/buildmaster/manager.py (+7/-1)
lib/lp/buildmaster/model/buildfarmjobbehavior.py (+3/-3)
lib/lp/buildmaster/tests/buildfarmjobbehavior.txt (+2/-2)
lib/lp/soyuz/doc/buildd-dispatching.txt (+3/-0)
lib/lp/soyuz/interfaces/builder.py (+11/-11)
lib/lp/soyuz/model/binarypackagebuildbehavior.py (+47/-74)
lib/lp/soyuz/model/builder.py (+74/-37)
lib/lp/soyuz/model/buildpackagejob.py (+6/-7)
lib/lp/soyuz/tests/soyuzbuilddhelpers.py (+11/-0)
To merge this branch: bzr merge lp:~jml/launchpad/behavior-refactor
Reviewer Review Type Date Requested Status
Michael Nelson (community) code Approve
Review via email: mp+17127@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Jonathan Lange (jml) wrote :

Beef up the BuilderSlave object a bit, and remove useless parameters from the IBuildFarmJobBehavior interface, change the IBuilder interface so that it no longer delegates to IBuildFarmJobBehaviour.

Revision history for this message
Michael Nelson (michael.nelson) wrote :

Thanks for cleaning up and making it a lot easier to read Jonathan.

You're fixing up the incorrect docstring, which was the only issue I saw.

Cheers.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/cachedproperty.py'
2--- lib/canonical/cachedproperty.py 2009-06-25 05:30:52 +0000
3+++ lib/canonical/cachedproperty.py 2010-01-13 02:56:16 +0000
4@@ -7,6 +7,7 @@
5
6 __metaclass__ = type
7
8+# XXX: JonathanLange 2010-01-11 bug=505731: Move this to lp.services.
9
10 def cachedproperty(attrname_or_fn):
11 """A decorator for methods that makes them properties with their return
12
13=== modified file 'lib/lp/buildmaster/interfaces/buildfarmjobbehavior.py'
14--- lib/lp/buildmaster/interfaces/buildfarmjobbehavior.py 2009-12-24 06:44:57 +0000
15+++ lib/lp/buildmaster/interfaces/buildfarmjobbehavior.py 2010-01-13 02:56:16 +0000
16@@ -30,7 +30,7 @@
17 def setBuilder(builder):
18 """Sets the associated builder reference for this instance."""
19
20- def logStartBuild(build_queue_item, logger):
21+ def logStartBuild(logger):
22 """Log the start of a specific build queue item.
23
24 The form of the log message will vary depending on the type of build.
25@@ -38,21 +38,20 @@
26 :param logger: A logger to be used to log diagnostic information.
27 """
28
29- def dispatchBuildToSlave(build_queue_item, logger):
30+ def dispatchBuildToSlave(build_queue_item_id, logger):
31 """Dispatch a specific build to the slave.
32
33- :param build_queue_item: The `BuildQueueItem` that will be built.
34- :logger: A logger to be used to log diagnostic information.
35+ :param build_queue_item_id: An identifier for the build queue item.
36+ :param logger: A logger to be used to log diagnostic information.
37 """
38
39- def verifyBuildRequest(build_queue_item, logger):
40+ def verifyBuildRequest(logger):
41 """Carry out any pre-build checks.
42
43- :param build_queue_item: The `BuildQueueItem` that is to be built.
44- :logger: A logger to be used to log diagnostic information.
45+ :param logger: A logger to be used to log diagnostic information.
46 """
47
48- def slaveStatus(self, raw_slave_status):
49+ def slaveStatus(raw_slave_status):
50 """Return a dict of custom slave status values for this behavior.
51
52 :param raw_slave_status: The value returned by the build slave's
53
54=== modified file 'lib/lp/buildmaster/manager.py'
55--- lib/lp/buildmaster/manager.py 2010-01-11 21:54:24 +0000
56+++ lib/lp/buildmaster/manager.py 2010-01-13 02:56:16 +0000
57@@ -7,7 +7,7 @@
58
59 __all__ = [
60 'BaseDispatchResult',
61- 'BuilddManager'
62+ 'BuilddManager',
63 'FailDispatchResult',
64 'RecordingSlave',
65 'ResetDispatchResult',
66@@ -70,6 +70,7 @@
67 major slave-scanner throughput issue while avoiding large-scale changes to
68 its code base.
69 """
70+
71 def __init__(self, name, url, vm_host):
72 self.name = name
73 self.url = url
74@@ -81,6 +82,11 @@
75 def __repr__(self):
76 return '<%s:%s>' % (self.name, self.url)
77
78+ def cacheFile(self, logger, libraryfilealias):
79+ """Cache the file on the server."""
80+ self.ensurepresent(
81+ libraryfilealias.content.sha1, libraryfilealias.http_url, '', '')
82+
83 def ensurepresent(self, *args):
84 """Download files needed for the build."""
85 self.calls.append(('ensurepresent', args))
86
87=== modified file 'lib/lp/buildmaster/model/buildfarmjobbehavior.py'
88--- lib/lp/buildmaster/model/buildfarmjobbehavior.py 2009-12-04 12:49:25 +0000
89+++ lib/lp/buildmaster/model/buildfarmjobbehavior.py 2010-01-13 02:56:16 +0000
90@@ -33,7 +33,7 @@
91 """The builder should be set once and not changed."""
92 self._builder = builder
93
94- def verifyBuildRequest(self, build_queue_item, logger):
95+ def verifyBuildRequest(self, logger):
96 """The default behavior is a no-op."""
97 pass
98
99@@ -55,12 +55,12 @@
100 """
101 super(IdleBuildBehavior, self).__init__(None)
102
103- def logStartBuild(self, build_queue_item, logger):
104+ def logStartBuild(self, logger):
105 """See `IBuildFarmJobBehavior`."""
106 raise BuildBehaviorMismatch(
107 "Builder was idle when asked to log the start of a build.")
108
109- def dispatchBuildToSlave(self, build_queue_item, logger):
110+ def dispatchBuildToSlave(self, build_queue_item_id, logger):
111 """See `IBuildFarmJobBehavior`."""
112 raise BuildBehaviorMismatch(
113 "Builder was idle when asked to dispatch a build to the slave.")
114
115=== modified file 'lib/lp/buildmaster/tests/buildfarmjobbehavior.txt'
116--- lib/lp/buildmaster/tests/buildfarmjobbehavior.txt 2009-12-04 12:49:25 +0000
117+++ lib/lp/buildmaster/tests/buildfarmjobbehavior.txt 2010-01-13 02:56:16 +0000
118@@ -31,7 +31,7 @@
119 ... """A custom build behavior for building blah."""
120 ... implements(IBuildFarmJobBehavior)
121 ...
122- ... def dispatchBuildToSlave(self, build_queue_item, logger):
123+ ... def dispatchBuildToSlave(self, build_queue_item_id, logger):
124 ... print "Did something special to dispatch MySpecialBuild."
125 ...
126 ... @property
127@@ -127,7 +127,7 @@
128 idle, such as making a call to log the start of a build, will raise an
129 appropriate exception.
130
131- >>> bob.logStartBuild(None, None)
132+ >>> bob.current_build_behavior.logStartBuild(None)
133 Traceback (most recent call last):
134 ...
135 BuildBehaviorMismatch: Builder was idle when asked to log the start of a
136
137=== modified file 'lib/lp/soyuz/doc/buildd-dispatching.txt'
138--- lib/lp/soyuz/doc/buildd-dispatching.txt 2010-01-10 23:08:55 +0000
139+++ lib/lp/soyuz/doc/buildd-dispatching.txt 2010-01-13 02:56:16 +0000
140@@ -121,6 +121,8 @@
141 False
142 >>> bob_builder.is_available
143 True
144+ >>> bob_builder.builderok
145+ True
146
147
148 == Builder dispatching API ==
149@@ -167,6 +169,7 @@
150 >>> dispatched_job = bob_builder.findAndStartJob()
151 >>> job == dispatched_job
152 True
153+ >>> bob_builder.builderok = True
154
155 >>> flush_database_updates()
156
157
158=== modified file 'lib/lp/soyuz/interfaces/builder.py'
159--- lib/lp/soyuz/interfaces/builder.py 2010-01-10 23:59:31 +0000
160+++ lib/lp/soyuz/interfaces/builder.py 2010-01-13 02:56:16 +0000
161@@ -12,6 +12,7 @@
162 'BuildJobMismatch',
163 'BuildSlaveFailure',
164 'CannotBuild',
165+ 'CannotFetchFile',
166 'CannotResumeHost',
167 'IBuilder',
168 'IBuilderSet',
169@@ -34,6 +35,15 @@
170 """The class of errors raised by the buildd classes"""
171
172
173+class CannotFetchFile(BuildDaemonError):
174+ """The slave was unable to fetch the file."""
175+
176+ def __init__(self, file_url, error_information):
177+ super(CannotFetchFile, self).__init__()
178+ self.file_url = file_url
179+ self.error_information = error_information
180+
181+
182 class ProtocolVersionMismatch(BuildDaemonError):
183 """The build slave had a protocol version. This is a serious error."""
184
185@@ -59,7 +69,7 @@
186 """The build slave has suffered an error and cannot be used."""
187
188
189-class IBuilder(IHasOwner, IBuildFarmJobBehavior):
190+class IBuilder(IHasOwner):
191 """Build-slave information and state.
192
193 Builder instance represents a single builder slave machine within the
194@@ -144,16 +154,6 @@
195 title=u"The current behavior of the builder for the current job.",
196 required=False)
197
198- def cacheFileOnSlave(logger, libraryfilealias):
199- """Ask the slave to cache a librarian file to its local disk.
200-
201- This is used in preparation for a build.
202-
203- :param logger: A logger used for providing debug information.
204- :param libraryfilealias: A library file alias representing the needed
205- file.
206- """
207-
208 def checkCanBuildForDistroArchSeries(distro_arch_series):
209 """Check that the slave can compile for the given distro_arch_release.
210
211
212=== modified file 'lib/lp/soyuz/model/binarypackagebuildbehavior.py'
213--- lib/lp/soyuz/model/binarypackagebuildbehavior.py 2009-12-03 14:38:48 +0000
214+++ lib/lp/soyuz/model/binarypackagebuildbehavior.py 2010-01-13 02:56:16 +0000
215@@ -11,9 +11,7 @@
216 'BinaryPackageBuildBehavior',
217 ]
218
219-import socket
220-import xmlrpclib
221-
222+from canonical.cachedproperty import cachedproperty
223 from canonical.launchpad.webapp import urlappend
224 from lp.buildmaster.interfaces.buildfarmjobbehavior import (
225 IBuildFarmJobBehavior)
226@@ -23,10 +21,8 @@
227 from lp.soyuz.adapters.archivedependencies import (
228 get_primary_current_component, get_sources_list_for_building)
229 from lp.soyuz.interfaces.archive import ArchivePurpose
230-from lp.soyuz.interfaces.build import IBuildSet
231-from lp.soyuz.interfaces.builder import BuildSlaveFailure, CannotBuild
232+from lp.soyuz.interfaces.builder import CannotBuild
233
234-from zope.component import getUtility
235 from zope.interface import implements
236
237
238@@ -35,91 +31,77 @@
239
240 implements(IBuildFarmJobBehavior)
241
242- def logStartBuild(self, build_queue_item, logger):
243+ @cachedproperty
244+ def build(self):
245+ return self.buildfarmjob.build
246+
247+ def logStartBuild(self, logger):
248 """See `IBuildFarmJobBehavior`."""
249- build = getUtility(IBuildSet).getByQueueEntry(build_queue_item)
250- spr = build.sourcepackagerelease
251-
252+ spr = self.build.sourcepackagerelease
253 logger.info("startBuild(%s, %s, %s, %s)", self._builder.url,
254- spr.name, spr.version, build.pocket.title)
255+ spr.name, spr.version, self.build.pocket.title)
256
257 @property
258 def status(self):
259 """See `IBuildFarmJobBehavior`."""
260- build = getUtility(IBuildSet).getByQueueEntry(
261- self._builder.currentjob)
262- msg = 'Building %s' % build.title
263- archive = build.archive
264+ msg = 'Building %s' % self.build.title
265+ archive = self.build.archive
266 if not archive.owner.private and (archive.is_ppa or archive.is_copy):
267 return '%s [%s/%s]' % (msg, archive.owner.name, archive.name)
268 else:
269 return msg
270
271- def dispatchBuildToSlave(self, build_queue_item, logger):
272+ def dispatchBuildToSlave(self, build_queue_id, logger):
273 """See `IBuildFarmJobBehavior`."""
274
275 # Start the binary package build on the slave builder. First
276 # we send the chroot.
277- build = getUtility(IBuildSet).getByQueueEntry(build_queue_item)
278- chroot = build.distroarchseries.getChroot()
279- self._builder.cacheFileOnSlave(logger, chroot)
280+ chroot = self.build.distroarchseries.getChroot()
281+ self._builder.slave.cacheFile(logger, chroot)
282
283 # Build filemap structure with the files required in this build
284 # and send them to the slave.
285 # If the build is private we tell the slave to get the files from the
286 # archive instead of the librarian because the slaves cannot
287 # access the restricted librarian.
288- private = build.archive.private
289+ private = self.build.archive.private
290 if private:
291- self._cachePrivateSourceOnSlave(build_queue_item, logger)
292+ self._cachePrivateSourceOnSlave(logger)
293 filemap = {}
294- for source_file in build.sourcepackagerelease.files:
295+ for source_file in self.build.sourcepackagerelease.files:
296 lfa = source_file.libraryfile
297 filemap[lfa.filename] = lfa.content.sha1
298 if not private:
299- self._builder.cacheFileOnSlave(
300- logger, source_file.libraryfile)
301+ self._builder.slave.cacheFile(logger, source_file.libraryfile)
302
303 # Generate a string which can be used to cross-check when obtaining
304 # results so we know we are referring to the right database object in
305 # subsequent runs.
306- buildid = "%s-%s" % (build.id, build_queue_item.id)
307+ buildid = "%s-%s" % (self.build.id, build_queue_id)
308 chroot_sha1 = chroot.content.sha1
309 logger.debug(
310 "Initiating build %s on %s" % (buildid, self._builder.url))
311
312- try:
313- args = self._extraBuildArgs(build)
314- status, info = self._builder.slave.build(
315- buildid, "debian", chroot_sha1, filemap, args)
316- message = """%s (%s):
317- ***** RESULT *****
318- %s
319- %s
320- %s: %s
321- ******************
322- """ % (
323- self._builder.name,
324- self._builder.url,
325- filemap,
326- args,
327- status,
328- info,
329- )
330- logger.info(message)
331- except xmlrpclib.Fault, info:
332- # Mark builder as 'failed'.
333- logger.debug(
334- "Disabling builder: %s" % self._builder.url, exc_info=1)
335- self._builder.failbuilder(
336- "Exception (%s) when setting up to new job" % info)
337- raise BuildSlaveFailure
338- except socket.error, info:
339- error_message = "Exception (%s) when setting up new job" % info
340- self._builder.handleTimeout(logger, error_message)
341- raise BuildSlaveFailure
342+ args = self._extraBuildArgs(self.build)
343+ status, info = self._builder.slave.build(
344+ buildid, "debian", chroot_sha1, filemap, args)
345+ message = """%s (%s):
346+ ***** RESULT *****
347+ %s
348+ %s
349+ %s: %s
350+ ******************
351+ """ % (
352+ self._builder.name,
353+ self._builder.url,
354+ filemap,
355+ args,
356+ status,
357+ info,
358+ )
359+ logger.info(message)
360
361- def verifyBuildRequest(self, build_queue_item, logger):
362+ def verifyBuildRequest(self, logger):
363 """Assert some pre-build checks.
364
365 The build request is checked:
366@@ -128,7 +110,7 @@
367 * Ensure that the build pocket allows builds for the current
368 distroseries state.
369 """
370- build = getUtility(IBuildSet).getByQueueEntry(build_queue_item)
371+ build = self.build
372 assert not (not self._builder.virtualized and build.is_virtualized), (
373 "Attempt to build non-virtual item on a virtual builder.")
374
375@@ -149,8 +131,7 @@
376 "Missing CHROOT for %s/%s/%s" % (
377 build.distroseries.distribution.name,
378 build.distroseries.name,
379- build.distroarchseries.architecturetag)
380- )
381+ build.distroarchseries.architecturetag))
382
383 # The main distribution has policies to prevent uploads to some
384 # pockets (e.g. security) during different parts of the distribution
385@@ -196,16 +177,9 @@
386
387 return extra_info
388
389- def _cachePrivateSourceOnSlave(self, build_queue_item, logger):
390+ def _cachePrivateSourceOnSlave(self, logger):
391 """Ask the slave to download source files for a private build.
392
393- The slave will cache the files for the source in build_queue_item
394- to its local disk in preparation for a private build. Private builds
395- will always take the source files from the archive rather than the
396- librarian since the archive has more granular access to each
397- archive's files.
398-
399- :param build_queue_item: The `IBuildQueue` being built.
400 :param logger: A logger used for providing debug information.
401 """
402 # The URL to the file in the archive consists of these parts:
403@@ -215,21 +189,20 @@
404 # Avoid circular imports.
405 from lp.soyuz.model.publishing import makePoolPath
406
407- build = getUtility(IBuildSet).getByQueueEntry(build_queue_item)
408- archive = build.archive
409+ archive = self.build.archive
410 archive_url = archive.archive_url
411- component_name = build.current_component.name
412- for source_file in build.sourcepackagerelease.files:
413+ component_name = self.build.current_component.name
414+ for source_file in self.build.sourcepackagerelease.files:
415 file_name = source_file.libraryfile.filename
416 sha1 = source_file.libraryfile.content.sha1
417- source_name = build.sourcepackagerelease.sourcepackagename.name
418- poolpath = makePoolPath(source_name, component_name)
419+ spn = self.build.sourcepackagerelease.sourcepackagename
420+ poolpath = makePoolPath(spn.name, component_name)
421 url = urlappend(archive_url, poolpath)
422 url = urlappend(url, file_name)
423 logger.debug("Asking builder on %s to ensure it has file %s "
424 "(%s, %s)" % (
425 self._builder.url, file_name, url, sha1))
426- self._builder._sendFileToSlave(
427+ self._builder.slave._sendFileToSlave(
428 url, sha1, "buildd", archive.buildd_secret)
429
430 def _extraBuildArgs(self, build):
431
432=== modified file 'lib/lp/soyuz/model/builder.py'
433--- lib/lp/soyuz/model/builder.py 2010-01-11 03:03:19 +0000
434+++ lib/lp/soyuz/model/builder.py 2010-01-13 02:56:16 +0000
435@@ -20,8 +20,6 @@
436 import urllib2
437 import xmlrpclib
438
439-from lazr.delegates import delegates
440-
441 from zope.interface import implements
442 from zope.component import getUtility
443
444@@ -34,7 +32,7 @@
445 from canonical.config import config
446 from canonical.buildd.slave import BuilderStatus
447 from lp.buildmaster.interfaces.buildfarmjobbehavior import (
448- BuildBehaviorMismatch, IBuildFarmJobBehavior)
449+ BuildBehaviorMismatch)
450 from lp.buildmaster.master import BuilddMaster
451 from lp.buildmaster.model.buildfarmjobbehavior import IdleBuildBehavior
452 from canonical.database.sqlbase import SQLBase, sqlvalues
453@@ -49,8 +47,8 @@
454 from lp.soyuz.interfaces.archive import ArchivePurpose
455 from lp.soyuz.interfaces.build import BuildStatus, IBuildSet
456 from lp.soyuz.interfaces.builder import (
457- BuildDaemonError, BuildSlaveFailure, CannotBuild, CannotResumeHost,
458- IBuilder, IBuilderSet, ProtocolVersionMismatch)
459+ BuildDaemonError, BuildSlaveFailure, CannotBuild, CannotFetchFile,
460+ CannotResumeHost, IBuilder, IBuilderSet, ProtocolVersionMismatch)
461 from lp.soyuz.interfaces.buildqueue import IBuildQueueSet
462 from lp.soyuz.interfaces.publishing import (
463 PackagePublishingStatus)
464@@ -61,6 +59,7 @@
465
466
467 class TimeoutHTTPConnection(httplib.HTTPConnection):
468+
469 def connect(self):
470 """Override the standard connect() methods to set a timeout"""
471 ret = httplib.HTTPConnection.connect(self)
472@@ -74,12 +73,13 @@
473
474 class TimeoutTransport(xmlrpclib.Transport):
475 """XMLRPC Transport to setup a socket with defined timeout"""
476+
477 def make_connection(self, host):
478 host, extra_headers, x509 = self.get_host_info(host)
479 return TimeoutHTTP(host)
480
481
482-class BuilderSlave(xmlrpclib.Server):
483+class BuilderSlave(xmlrpclib.ServerProxy):
484 """Add in a few useful methods for the XMLRPC slave."""
485
486 def __init__(self, urlbase, vm_host):
487@@ -114,11 +114,48 @@
488
489 return (stdout, stderr, resume_process.returncode)
490
491+ def cacheFile(self, logger, libraryfilealias):
492+ """Make sure that the file at 'libraryfilealias' is on the slave.
493+
494+ :param logger: A python `Logger` object.
495+ :param libraryfilealias: An `ILibraryFileAlias`.
496+ """
497+ url = libraryfilealias.http_url
498+ logger.debug("Asking builder on %s to ensure it has file %s "
499+ "(%s, %s)" % (self.urlbase, libraryfilealias.filename,
500+ url, libraryfilealias.content.sha1))
501+ self._sendFileToSlave(url, libraryfilealias.content.sha1)
502+
503+ def _sendFileToSlave(self, url, sha1, username="", password=""):
504+ """Helper to send the file at 'url' with 'sha1' to this builder."""
505+ present, info = self.ensurepresent(sha1, url, username, password)
506+ if not present:
507+ raise CannotFetchFile(url, info)
508+
509+ def build(self, buildid, builder_type, chroot_sha1, filemap, args):
510+ """Build a thing on this build slave.
511+
512+ :param buildid: A string identifying this build.
513+ :param builder_type: The type of builder needed.
514+ :param chroot_sha1: XXX
515+ :param filemap: A dictionary mapping from paths to SHA-1 hashes of
516+ the file contents.
517+ :param args: A dictionary of extra arguments. The contents depend on
518+ the build job type.
519+ """
520+ # Can't upcall to xmlrpclib.ServerProxy, since it doesn't actually
521+ # have a 'build' method.
522+ build_method = xmlrpclib.ServerProxy.__getattr__(self, 'build')
523+ try:
524+ return build_method(
525+ self, buildid, builder_type, chroot_sha1, filemap, args)
526+ except xmlrpclib.Fault, info:
527+ raise BuildSlaveFailure(info)
528+
529
530 class Builder(SQLBase):
531
532 implements(IBuilder, IHasBuildRecords)
533- delegates(IBuildFarmJobBehavior, context="current_build_behavior")
534 _table = 'Builder'
535
536 _defaultOrder = ['id']
537@@ -168,7 +205,6 @@
538 # we just return it.
539 return self._current_build_behavior
540
541-
542 def _setCurrentBuildBehavior(self, new_behavior):
543 """Set the current build behavior."""
544 self._current_build_behavior = new_behavior
545@@ -178,31 +214,6 @@
546 current_build_behavior = property(
547 _getCurrentBuildBehavior, _setCurrentBuildBehavior)
548
549- def cacheFileOnSlave(self, logger, libraryfilealias):
550- """See `IBuilder`."""
551- url = libraryfilealias.http_url
552- logger.debug("Asking builder on %s to ensure it has file %s "
553- "(%s, %s)" % (self.url, libraryfilealias.filename,
554- url, libraryfilealias.content.sha1))
555- self._sendFileToSlave(url, libraryfilealias.content.sha1)
556-
557- def _sendFileToSlave(self, url, sha1, username="", password=""):
558- """Helper to send the file at 'url' with 'sha1' to this builder."""
559- if not self.builderok:
560- raise BuildDaemonError("Attempted to give a file to a known-bad"
561- " builder")
562- present, info = self.slave.ensurepresent(
563- sha1, url, username, password)
564- if not present:
565- message = """Slave '%s' (%s) was unable to fetch file.
566- ****** URL ********
567- %s
568- ****** INFO *******
569- %s
570- *******************
571- """ % (self.name, self.url, url, info)
572- raise BuildDaemonError(message)
573-
574 def checkCanBuildForDistroArchSeries(self, distro_arch_series):
575 """See IBuilder."""
576 # XXX cprov 2007-06-15:
577@@ -277,12 +288,16 @@
578
579 def startBuild(self, build_queue_item, logger):
580 """See IBuilder."""
581- # Set the build behavior depending on the provided build queue item.
582 self.current_build_behavior = build_queue_item.required_build_behavior
583- self.logStartBuild(build_queue_item, logger)
584+ self.current_build_behavior.logStartBuild(logger)
585
586 # Make sure the request is valid; an exception is raised if it's not.
587- self.verifyBuildRequest(build_queue_item, logger)
588+ self.current_build_behavior.verifyBuildRequest(logger)
589+
590+ # Set the build behavior depending on the provided build queue item.
591+ if not self.builderok:
592+ raise BuildDaemonError(
593+ "Attempted to start a build on a known-bad builder.")
594
595 # If we are building a virtual build, resume the virtual machine.
596 if self.virtualized:
597@@ -290,12 +305,33 @@
598
599 # Do it.
600 build_queue_item.markAsBuilding(self)
601- self.dispatchBuildToSlave(build_queue_item, logger)
602+ try:
603+ self.current_build_behavior.dispatchBuildToSlave(
604+ build_queue_item.id, logger)
605+ except BuildSlaveFailure, e:
606+ logger.debug("Disabling builder: %s" % self.url, exc_info=1)
607+ self.failbuilder(
608+ "Exception (%s) when setting up to new job" % (e,))
609+ except CannotFetchFile, e:
610+ message = """Slave '%s' (%s) was unable to fetch file.
611+ ****** URL ********
612+ %s
613+ ****** INFO *******
614+ %s
615+ *******************
616+ """ % (self.name, self.url, e.file_url, e.error_information)
617+ raise BuildDaemonError(message)
618+ except socket.error, e:
619+ error_message = "Exception (%s) when setting up new job" % (e,)
620+ self.handleTimeout(logger, error_message)
621+ raise BuildSlaveFailure
622+
623
624 # XXX cprov 2009-06-24: This code does not belong to the content
625 # class domain. Here we cannot make sensible decisions about what
626 # we are allowed to present according to the request user. Then
627 # bad things happens, see bug #391721.
628+
629 @property
630 def status(self):
631 """See IBuilder"""
632@@ -317,6 +353,7 @@
633 # that the builder history will display binary build records, as
634 # returned by getBuildRecords() below. See the bug for a discussion
635 # of the options.
636+
637 def getBuildRecords(self, build_state=None, name=None, arch_tag=None,
638 user=None):
639 """See IHasBuildRecords."""
640
641=== modified file 'lib/lp/soyuz/model/buildpackagejob.py'
642--- lib/lp/soyuz/model/buildpackagejob.py 2010-01-07 05:32:58 +0000
643+++ lib/lp/soyuz/model/buildpackagejob.py 2010-01-13 02:56:16 +0000
644@@ -16,7 +16,7 @@
645 from canonical.database.sqlbase import sqlvalues
646
647 from lp.buildmaster.interfaces.buildfarmjob import (
648- BuildFarmJobType, IBuildFarmJob, IBuildFarmJobDispatchEstimation)
649+ BuildFarmJobType, IBuildFarmJobDispatchEstimation)
650 from lp.registry.interfaces.sourcepackage import SourcePackageUrgency
651 from lp.registry.interfaces.pocket import PackagePublishingPocket
652 from lp.services.job.interfaces.job import JobStatus
653@@ -27,7 +27,7 @@
654
655 class BuildPackageJob(Storm):
656 """See `IBuildPackageJob`."""
657- implements(IBuildFarmJob, IBuildPackageJob)
658+ implements(IBuildPackageJob)
659 classProvides(IBuildFarmJobDispatchEstimation)
660
661 __storm_table__ = 'buildpackagejob'
662@@ -54,7 +54,7 @@
663 'universe': 250,
664 'restricted': 750,
665 'main': 1000,
666- 'partner' : 1250,
667+ 'partner': 1250,
668 }
669
670 score_urgency = {
671@@ -146,8 +146,8 @@
672 # buildlog_ubuntu_dapper_i386_foo_1.0-ubuntu0_FULLYBUILT.txt
673 # it fix request from bug # 30617
674 return ('buildlog_%s-%s-%s.%s_%s_%s.txt' % (
675- distroname, distroseriesname, archname, sourcename, version, state
676- ))
677+ distroname, distroseriesname, archname, sourcename, version,
678+ state))
679
680 def getName(self):
681 """See `IBuildPackageJob`."""
682@@ -176,7 +176,7 @@
683 def composePendingJobsQuery(min_score, processor, virtualized):
684 """See `IBuildFarmJob`."""
685 return """
686- SELECT
687+ SELECT
688 BuildQueue.job,
689 BuildQueue.lastscore,
690 BuildQueue.estimated_duration,
691@@ -209,4 +209,3 @@
692 def virtualized(self):
693 """See `IBuildFarmJob`."""
694 return self.build.is_virtualized
695-
696
697=== modified file 'lib/lp/soyuz/tests/soyuzbuilddhelpers.py'
698--- lib/lp/soyuz/tests/soyuzbuilddhelpers.py 2009-06-25 04:06:00 +0000
699+++ lib/lp/soyuz/tests/soyuzbuilddhelpers.py 2010-01-13 02:56:16 +0000
700@@ -26,6 +26,7 @@
701 import xmlrpclib
702
703 from canonical.config import config
704+from lp.soyuz.interfaces.builder import CannotFetchFile
705
706
707 class MockBuilder:
708@@ -185,6 +186,16 @@
709
710 return (stdout, stderr, resume_process.returncode)
711
712+ def _sendFileToSlave(self, url, sha1, username="", password=""):
713+ present, info = self.ensurepresent(sha1, url, username, password)
714+ if not present:
715+ raise CannotFetchFile(url, info)
716+
717+ def cacheFile(self, logger, libraryfilealias):
718+ self._sendFileToSlave(
719+ libraryfilealias.http_url, libraryfilealias.content.sha1)
720+
721+
722 class BuildingSlave(OkSlave):
723 """A mock slave that looks like it's currently building."""
724