Merge lp:~jml/launchpad/behavior-refactor into lp:launchpad
- behavior-refactor
- Merge into devel
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Nelson (community) | code | Approve | |
Review via email: mp+17127@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Jonathan Lange (jml) wrote : | # |
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 |
Beef up the BuilderSlave object a bit, and remove useless parameters from the IBuildFarmJobBe havior interface, change the IBuilder interface so that it no longer delegates to IBuildFarmJobBe haviour.