1
1
# Copyright Canonical Limited
2
# Author: Daniel Silverstone <daniel.silverstone@canonical.com>
2
# Authors: Daniel Silverstone <daniel.silverstone@canonical.com>
3
# and Adam Conrad <adam.conrad@canonical.com>
4
5
# Buildd Slave implementation
168
169
WAITING = "BuilderStatus.WAITING"
169
170
ABORTING = "BuilderStatus.ABORTING"
170
171
ABORTED = "BuilderStatus.ABORTED"
172
173
UNKNOWNSUM = "BuilderStatus.UNKNOWNSUM"
173
174
UNKNOWNBUILDER = "BuilderStatus.UNKNOWNBUILDER"
179
180
OK = "BuildStatus.OK"
180
181
DEPFAIL = "BuildStatus.DEPFAIL"
182
GIVENBACK = "BuildStatus.GIVENBACK"
181
183
PACKAGEFAIL = "BuildStatus.PACKAGEFAIL"
182
184
CHROOTFAIL = "BuildStatus.CHROOTFAIL"
183
185
BUILDERFAIL = "BuildStatus.BUILDERFAIL"
185
188
class BuildDSlave(object):
186
189
"""Build Daemon slave. Implementation of most needed functions
187
190
for a Build-Slave device.
213
217
Optionally you can provide the librarian URL and
214
218
the build slave will fetch the file if it doesn't have it.
219
Return a tuple containing: (<present>, <info>)
221
extra_info = 'No URL'
216
222
if url is not None:
217
224
if not os.path.exists(self.cachePath(sha1sum)):
218
225
self.log('Fetching %s by url %s' % (sha1sum, url))
220
227
f = urllib2.urlopen(url)
222
self.log('Error accessing Librarian: %s' % e)
228
except Exception, info:
229
extra_info = 'Error accessing Librarian: %s' % info
230
self.log(extra_info, exc_info=True)
224
232
of = open(self.cachePath(sha1sum), "w")
225
233
# Upped for great justice to 256k
229
237
check_sum.update(chunk)
240
extra_info = 'Download'
232
241
if check_sum.hexdigest() != sha1sum:
233
242
os.remove(self.cachePath(sha1sum))
234
self.log("Digests did not match, removing again!")
235
return os.path.exists(self.cachePath(sha1sum))
243
extra_info = "Digests did not match, removing again!"
245
return (os.path.exists(self.cachePath(sha1sum)), extra_info)
237
247
def storeFile(self, content):
238
248
"""Take the provided content and store it in the file cache."""
239
249
sha1sum = sha.sha(content).hexdigest()
240
if self.ensurePresent(sha1sum):
250
present, info = self.ensurePresent(sha1sum)
242
253
f = open(self.cachePath(sha1sum), "w")
247
258
def fetchFile(self, sha1sum):
248
259
"""Fetch the file of the given sha1sum."""
249
if not self.ensurePresent(sha1sum):
260
present, info = self.ensurePresent(sha1sum)
250
262
raise ValueError("Unknown SHA1sum %s" % sha1sum)
251
263
f = open(self.cachePath(sha1sum), "r")
342
354
def buildFail(self):
343
355
"""Cease building because the package failed to build."""
344
356
if self.builderstatus != BuilderStatus.BUILDING:
345
raise ValueError("Slave is not BUILDING when set to BUILDFAIL")
357
raise ValueError("Slave is not BUILDING when set to PACKAGEFAIL")
346
358
self.builderstatus = BuilderStatus.WAITING
347
359
self.buildstatus = BuildStatus.PACKAGEFAIL
361
def depFail(self, dependencies):
350
362
"""Cease building due to a dependency issue."""
351
363
if self.builderstatus != BuilderStatus.BUILDING:
352
364
raise ValueError("Slave is not BUILDING when set to DEPFAIL")
353
365
self.builderstatus = BuilderStatus.WAITING
354
366
self.buildstatus = BuildStatus.DEPFAIL
367
self.builddependencies = dependencies
370
"""Give-back package due to a transient buildd/archive issue."""
371
if self.builderstatus != BuilderStatus.BUILDING:
372
raise ValueError("Slave is not BUILDING when set to GIVENBACK")
373
self.builderstatus = BuilderStatus.WAITING
374
self.buildstatus = BuildStatus.GIVENBACK
356
376
def buildComplete(self):
357
377
"""Mark the build as complete and waiting interaction from the build
431
451
if self.slave.buildstatus in (BuildStatus.OK, BuildStatus.PACKAGEFAIL,
432
452
BuildStatus.DEPFAIL):
433
453
return (self.slave.buildstatus, self.buildid,
434
self.slave.waitingfiles)
454
self.slave.waitingfiles, self.slave.builddependencies)
435
455
return (self.slave.buildstatus, self.buildid)
437
457
def status_ABORTED(self):
466
486
return BuilderStatus.IDLE
468
488
def xmlrpc_build(self, buildid, builder, chrootsum, filemap, args):
489
"""Check if requested arguments are sane and initiate build procedure
491
return a tuple containing: (<builder_status>, <info>)
494
# check requested builder
469
495
if not builder in self._builders:
470
return BuilderStatus.UNKNOWNBUILDER
471
if not self.slave.ensurePresent(chrootsum):
472
return BuilderStatus.UNKNOWNSUM, chrootsum
473
for checksum in filemap.itervalues():
474
if not self.slave.ensurePresent(checksum):
475
return BuilderStatus.UNKNOWNSUM, checksum
496
return (BuilderStatus.UNKNOWNBUILDER, None)
497
# check requested chroot availability
498
chroot_present, info = self.slave.ensurePresent(chrootsum)
499
if not chroot_present:
500
extra_info = """CHROOTSUM -> %s
504
""" % (chrootsum, info)
505
return (BuilderStatus.UNKNOWNSUM, extra_info)
506
# check requested files availability
507
for filesum in filemap.itervalues():
508
file_present, info = self.slave.ensurePresent(filesum)
510
extra_info = """FILESUM -> %s
514
""" % (filesum, info)
515
return (BuilderStatus.UNKNOWNSUM, extra_info)
516
# check buildid sanity
476
517
if buildid is None or buildid == "" or buildid == 0:
477
518
raise ValueError(buildid)
478
520
# builder is available, buildd is non empty,
479
521
# filelist is consistent, chrootsum is available, let's initiate...
481
522
self.buildid = buildid
483
523
self.slave.startBuild(self._builders[builder](self.slave, buildid))
484
524
self.slave.manager.initiate(filemap, chrootsum, args)
485
return BuilderStatus.BUILDING
525
return (BuilderStatus.BUILDING, buildid)