~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/buildmaster/model/packagebuild.py

  • Committer: Launchpad Patch Queue Manager
  • Date: 2012-01-05 16:22:45 UTC
  • mfrom: (14584.1.3 fix-retest-colorize)
  • Revision ID: launchpad@pqm.canonical.com-20120105162245-cvhcg00ousz00rtu
[r=allenap][no-qa] Remove terminal color codes from input in
 bin/retest.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright 2010-2011 Canonical Ltd.  This software is licensed under the
 
1
# Copyright 2010 Canonical Ltd.  This software is licensed under the
2
2
# GNU Affero General Public License version 3 (see the file LICENSE).
3
3
 
4
4
__metaclass__ = type
24
24
    Storm,
25
25
    Unicode,
26
26
    )
27
 
import transaction
28
27
from zope.component import getUtility
29
28
from zope.interface import (
30
29
    classProvides,
51
50
from lp.services.config import config
52
51
from lp.services.database.enumcol import DBEnum
53
52
from lp.services.database.lpstorm import IMasterStore
54
 
from lp.services.database.transaction_policy import DatabaseTransactionPolicy
55
53
from lp.services.helpers import filenameToContentType
56
54
from lp.services.librarian.browser import ProxiedLibraryFileAlias
57
55
from lp.services.librarian.interfaces import ILibraryFileAliasSet
179
177
    def storeBuildInfo(build, librarian, slave_status):
180
178
        """See `IPackageBuild`."""
181
179
        def got_log(lfa_id):
182
 
            dependencies = slave_status.get('dependencies')
183
 
            if dependencies is not None:
184
 
                dependencies = unicode(dependencies)
185
 
 
186
180
            # log, builder and date_finished are read-only, so we must
187
181
            # currently remove the security proxy to set them.
188
182
            naked_build = removeSecurityProxy(build)
189
 
 
190
 
            transaction.commit()
191
 
            with DatabaseTransactionPolicy(read_only=False):
192
 
                naked_build.log = lfa_id
193
 
                naked_build.builder = build.buildqueue_record.builder
194
 
                # XXX cprov 20060615 bug=120584: Currently buildduration
195
 
                # includes the scanner latency.  It should really be asking
196
 
                # the slave for the duration spent building locally.
197
 
                naked_build.date_finished = datetime.datetime.now(pytz.UTC)
198
 
                build.dependencies = dependencies
199
 
                transaction.commit()
 
183
            naked_build.log = lfa_id
 
184
            naked_build.builder = build.buildqueue_record.builder
 
185
            # XXX cprov 20060615 bug=120584: Currently buildduration includes
 
186
            # the scanner latency, it should really be asking the slave for
 
187
            # the duration spent building locally.
 
188
            naked_build.date_finished = datetime.datetime.now(pytz.UTC)
 
189
            if slave_status.get('dependencies') is not None:
 
190
                build.dependencies = unicode(slave_status.get('dependencies'))
 
191
            else:
 
192
                build.dependencies = None
200
193
 
201
194
        d = build.getLogFromSlave(build)
202
195
        return d.addCallback(got_log)
293
286
            job=job, processor=processor,
294
287
            virtualized=specific_job.virtualized)
295
288
        Store.of(self).add(queue_entry)
296
 
 
297
289
        return queue_entry
298
290
 
299
291
    def handleStatus(self, status, librarian, slave_status):
300
292
        """See `IPackageBuild`."""
301
 
        # Avoid circular imports.
302
293
        from lp.buildmaster.manager import BUILDD_MANAGER_LOG_NAME
303
 
 
304
294
        logger = logging.getLogger(BUILDD_MANAGER_LOG_NAME)
305
295
        send_notification = status in self.ALLOWED_STATUS_NOTIFICATIONS
306
296
        method = getattr(self, '_handleStatus_' + status, None)
307
297
        if method is None:
308
 
            logger.critical(
309
 
                "Unknown BuildStatus '%s' for builder '%s'",
310
 
                status, self.buildqueue_record.builder.url)
311
 
            return None
312
 
 
 
298
            logger.critical("Unknown BuildStatus '%s' for builder '%s'"
 
299
                            % (status, self.buildqueue_record.builder.url))
 
300
            return
313
301
        d = method(librarian, slave_status, logger, send_notification)
314
302
        return d
315
303
 
316
 
    def _destroy_buildqueue_record(self, unused_arg):
317
 
        """Destroy this build's `BuildQueue` record."""
318
 
        transaction.commit()
319
 
        with DatabaseTransactionPolicy(read_only=False):
320
 
            self.buildqueue_record.destroySelf()
321
 
            transaction.commit()
322
 
 
323
304
    def _release_builder_and_remove_queue_item(self):
324
305
        # Release the builder for another job.
325
306
        d = self.buildqueue_record.builder.cleanSlave()
326
307
        # Remove BuildQueue record.
327
 
        return d.addCallback(self._destroy_buildqueue_record)
328
 
 
329
 
    def _notify_if_appropriate(self, appropriate=True, extra_info=None):
330
 
        """If `appropriate`, call `self.notify` in a write transaction."""
331
 
        if appropriate:
332
 
            transaction.commit()
333
 
            with DatabaseTransactionPolicy(read_only=False):
334
 
                self.notify(extra_info=extra_info)
335
 
                transaction.commit()
 
308
        return d.addCallback(lambda x: self.buildqueue_record.destroySelf())
336
309
 
337
310
    def _handleStatus_OK(self, librarian, slave_status, logger,
338
311
                         send_notification):
348
321
            self.buildqueue_record.specific_job.build.title,
349
322
            self.buildqueue_record.builder.name))
350
323
 
351
 
        # If this is a binary package build for a source that is no
352
 
        # longer published, discard it.
 
324
        # If this is a binary package build, discard it if its source is
 
325
        # no longer published.
353
326
        if self.build_farm_job_type == BuildFarmJobType.PACKAGEBUILD:
354
327
            build = self.buildqueue_record.specific_job.build
355
328
            if not build.current_source_publication:
356
 
                transaction.commit()
357
 
                with DatabaseTransactionPolicy(read_only=False):
358
 
                    build.status = BuildStatus.SUPERSEDED
359
 
                    transaction.commit()
 
329
                build.status = BuildStatus.SUPERSEDED
360
330
                return self._release_builder_and_remove_queue_item()
361
331
 
362
 
        # Explode rather than collect a binary that is denied in this
363
 
        # distroseries/pocket.
 
332
        # Explode before collect a binary that is denied in this
 
333
        # distroseries/pocket
364
334
        if not self.archive.allowUpdatesToReleasePocket():
365
335
            assert self.distro_series.canUploadToPocket(self.pocket), (
366
336
                "%s (%s) can not be built for pocket %s: illegal status"
405
375
            # files from the slave.
406
376
            if successful_copy_from_slave:
407
377
                logger.info(
408
 
                    "Gathered %s %d completely. "
409
 
                    "Moving %s to uploader queue.",
410
 
                    self.__class__.__name__, self.id, upload_leaf)
 
378
                    "Gathered %s %d completely. Moving %s to uploader queue."
 
379
                    % (self.__class__.__name__, self.id, upload_leaf))
411
380
                target_dir = os.path.join(root, "incoming")
412
 
                resulting_status = BuildStatus.UPLOADING
 
381
                self.status = BuildStatus.UPLOADING
413
382
            else:
414
383
                logger.warning(
415
 
                    "Copy from slave for build %s was unsuccessful.",
416
 
                    self.id)
 
384
                    "Copy from slave for build %s was unsuccessful.", self.id)
 
385
                self.status = BuildStatus.FAILEDTOUPLOAD
 
386
                if send_notification:
 
387
                    self.notify(
 
388
                        extra_info='Copy from slave was unsuccessful.')
417
389
                target_dir = os.path.join(root, "failed")
418
 
                resulting_status = BuildStatus.FAILEDTOUPLOAD
419
 
 
420
 
            transaction.commit()
421
 
            with DatabaseTransactionPolicy(read_only=False):
422
 
                self.status = resulting_status
423
 
                transaction.commit()
424
 
 
425
 
            if not successful_copy_from_slave:
426
 
                self._notify_if_appropriate(
427
 
                    send_notification, "Copy from slave was unsuccessful.")
428
390
 
429
391
            if not os.path.exists(target_dir):
430
392
                os.mkdir(target_dir)
432
394
            # Release the builder for another job.
433
395
            d = self._release_builder_and_remove_queue_item()
434
396
 
 
397
            # Commit so there are no race conditions with archiveuploader
 
398
            # about self.status.
 
399
            Store.of(self).commit()
 
400
 
435
401
            # Move the directory used to grab the binaries into
436
402
            # the incoming directory so the upload processor never
437
403
            # sees half-finished uploads.
455
421
        set the job status as FAILEDTOBUILD, store available info and
456
422
        remove Buildqueue entry.
457
423
        """
458
 
        transaction.commit()
459
 
        with DatabaseTransactionPolicy(read_only=False):
460
 
            self.status = BuildStatus.FAILEDTOBUILD
461
 
            transaction.commit()
 
424
        self.status = BuildStatus.FAILEDTOBUILD
462
425
 
463
426
        def build_info_stored(ignored):
464
 
            self._notify_if_appropriate(send_notification)
 
427
            if send_notification:
 
428
                self.notify()
465
429
            d = self.buildqueue_record.builder.cleanSlave()
466
 
            return d.addCallback(self._destroy_buildqueue_record)
 
430
            return d.addCallback(
 
431
                lambda x: self.buildqueue_record.destroySelf())
467
432
 
468
433
        d = self.storeBuildInfo(self, librarian, slave_status)
469
434
        return d.addCallback(build_info_stored)
476
441
        MANUALDEPWAIT, store available information, remove BuildQueue
477
442
        entry and release builder slave for another job.
478
443
        """
479
 
        with DatabaseTransactionPolicy(read_only=False):
480
 
            self.status = BuildStatus.MANUALDEPWAIT
481
 
            transaction.commit()
 
444
        self.status = BuildStatus.MANUALDEPWAIT
482
445
 
483
446
        def build_info_stored(ignored):
484
447
            logger.critical("***** %s is MANUALDEPWAIT *****"
485
448
                            % self.buildqueue_record.builder.name)
486
 
            self._notify_if_appropriate(send_notification)
 
449
            if send_notification:
 
450
                self.notify()
487
451
            d = self.buildqueue_record.builder.cleanSlave()
488
 
            return d.addCallback(self._destroy_buildqueue_record)
 
452
            return d.addCallback(
 
453
                lambda x: self.buildqueue_record.destroySelf())
489
454
 
490
455
        d = self.storeBuildInfo(self, librarian, slave_status)
491
456
        return d.addCallback(build_info_stored)
498
463
        job as CHROOTFAIL, store available information, remove BuildQueue
499
464
        and release the builder.
500
465
        """
501
 
        with DatabaseTransactionPolicy(read_only=False):
502
 
            self.status = BuildStatus.CHROOTWAIT
503
 
            transaction.commit()
 
466
        self.status = BuildStatus.CHROOTWAIT
504
467
 
505
468
        def build_info_stored(ignored):
506
 
            logger.critical(
507
 
                "***** %s is CHROOTWAIT *****",
508
 
                self.buildqueue_record.builder.name)
509
 
 
510
 
            self._notify_if_appropriate(send_notification)
 
469
            logger.critical("***** %s is CHROOTWAIT *****" %
 
470
                            self.buildqueue_record.builder.name)
 
471
            if send_notification:
 
472
                self.notify()
511
473
            d = self.buildqueue_record.builder.cleanSlave()
512
 
            return d.addCallback(self._destroy_buildqueue_record)
 
474
            return d.addCallback(
 
475
                lambda x: self.buildqueue_record.destroySelf())
513
476
 
514
477
        d = self.storeBuildInfo(self, librarian, slave_status)
515
478
        return d.addCallback(build_info_stored)
516
479
 
517
 
    def _reset_buildqueue_record(self, ignored_arg=None):
518
 
        """Reset the `BuildQueue` record, in a write transaction."""
519
 
        transaction.commit()
520
 
        with DatabaseTransactionPolicy(read_only=False):
521
 
            self.buildqueue_record.reset()
522
 
            transaction.commit()
523
 
 
524
480
    def _handleStatus_BUILDERFAIL(self, librarian, slave_status, logger,
525
481
                                  send_notification):
526
482
        """Handle builder failures.
534
490
        self.buildqueue_record.builder.failBuilder(
535
491
            "Builder returned BUILDERFAIL when asked for its status")
536
492
 
 
493
        def build_info_stored(ignored):
 
494
            # simply reset job
 
495
            self.buildqueue_record.reset()
537
496
        d = self.storeBuildInfo(self, librarian, slave_status)
538
 
        return d.addCallback(self._reset_buildqueue_record)
 
497
        return d.addCallback(build_info_stored)
539
498
 
540
499
    def _handleStatus_GIVENBACK(self, librarian, slave_status, logger,
541
500
                                send_notification):
555
514
            # the next Paris Summit, infinity has some ideas about how
556
515
            # to use this content. For now we just ensure it's stored.
557
516
            d = self.buildqueue_record.builder.cleanSlave()
558
 
            self._reset_buildqueue_record()
 
517
            self.buildqueue_record.reset()
559
518
            return d
560
519
 
561
520
        d = self.storeBuildInfo(self, librarian, slave_status)