~launchpad-pqm/launchpad/devel

10130.7.2 by Jonathan Lange
Initial recipe builder behaviour stuff.
1
# Copyright 2010 Canonical Ltd.  This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
3
4
"""Code to build recipes on the buildfarm."""
5
6
__metaclass__ = type
7
__all__ = [
8
    'RecipeBuildBehavior',
9
    ]
10
10795.2.2 by Julian Edwards
Ensure that recipe builds send a configured sources.list to the slave for an archive that contains the bzr-builder package
11
import traceback
12
10739.2.3 by Aaron Bentley
Fix lint errors.
13
from zope.component import adapts
10130.7.2 by Jonathan Lange
Initial recipe builder behaviour stuff.
14
from zope.interface import implements
12001.3.18 by j.c.sackett
Updated tests.
15
from zope.security.proxy import removeSecurityProxy
10130.7.2 by Jonathan Lange
Initial recipe builder behaviour stuff.
16
10795.2.2 by Julian Edwards
Ensure that recipe builds send a configured sources.list to the slave for an archive that contains the bzr-builder package
17
from canonical.config import config
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
18
from lp.buildmaster.interfaces.builder import CannotBuild
10130.7.2 by Jonathan Lange
Initial recipe builder behaviour stuff.
19
from lp.buildmaster.interfaces.buildfarmjobbehavior import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
20
    IBuildFarmJobBehavior,
21
    )
22
from lp.buildmaster.model.buildfarmjobbehavior import BuildFarmJobBehaviorBase
10130.12.22 by Michael Nelson
Updated imports.
23
from lp.code.interfaces.sourcepackagerecipebuild import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
24
    ISourcePackageRecipeBuildJob,
25
    )
10130.7.28 by Jelmer Vernooij
Provide a hardcoded pocket attribute on SourcePackageRecipeBuild.
26
from lp.registry.interfaces.pocket import PackagePublishingPocket
10130.7.27 by Jelmer Vernooij
Provide ogrecomponent.
27
from lp.soyuz.adapters.archivedependencies import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
28
    get_primary_current_component,
29
    get_sources_list_for_building,
30
    )
10130.7.2 by Jonathan Lange
Initial recipe builder behaviour stuff.
31
32
33
class RecipeBuildBehavior(BuildFarmJobBehaviorBase):
34
    """How to build a recipe on the build farm."""
35
10130.7.19 by Jelmer Vernooij
Merge Michael's recipe build model code.
36
    adapts(ISourcePackageRecipeBuildJob)
10130.7.2 by Jonathan Lange
Initial recipe builder behaviour stuff.
37
    implements(IBuildFarmJobBehavior)
38
39
    status = None
40
10130.7.25 by Jelmer Vernooij
feedback from jml
41
    @property
10130.7.14 by Jelmer Vernooij
Implement RecipeBuilder.logStartBuild.
42
    def build(self):
43
        return self.buildfarmjob.build
44
45
    @property
10130.7.25 by Jelmer Vernooij
feedback from jml
46
    def display_name(self):
7675.700.6 by Paul Hummer
Fixed the tests
47
        ret = "%s, %s, %s" % (
48
            self.build.distroseries.displayname, self.build.recipe.name,
49
            self.build.recipe.owner.name)
10130.7.14 by Jelmer Vernooij
Implement RecipeBuilder.logStartBuild.
50
        if self._builder is not None:
51
            ret += " (on %s)" % self._builder.url
52
        return ret
53
10130.7.2 by Jonathan Lange
Initial recipe builder behaviour stuff.
54
    def logStartBuild(self, logger):
10130.7.13 by Jelmer Vernooij
Make RecipeBuilder adapt IBuildSourcePackageFromRecipeJob.
55
        """See `IBuildFarmJobBehavior`."""
10130.7.25 by Jelmer Vernooij
feedback from jml
56
        logger.info("startBuild(%s)", self.display_name)
10130.7.2 by Jonathan Lange
Initial recipe builder behaviour stuff.
57
10795.2.2 by Julian Edwards
Ensure that recipe builds send a configured sources.list to the slave for an archive that contains the bzr-builder package
58
    def _extraBuildArgs(self, distroarchseries, logger=None):
10130.7.15 by Jelmer Vernooij
wip.
59
        """
60
        Return the extra arguments required by the slave for the given build.
61
        """
62
        # Build extra arguments.
63
        args = {}
10130.7.28 by Jelmer Vernooij
Provide a hardcoded pocket attribute on SourcePackageRecipeBuild.
64
        suite = self.build.distroseries.name
65
        if self.build.pocket != PackagePublishingPocket.RELEASE:
66
            suite += "-%s" % (self.build.pocket.name.lower())
67
        args['suite'] = suite
11121.3.2 by William Grant
Send arch_tag for all existing job types, and fix broken tests.
68
        args['arch_tag'] = distroarchseries.architecturetag
11315.1.1 by Tim Penhey
Handle the case where there is not a preferred email set.
69
        requester = self.build.requester
70
        if requester.preferredemail is None:
71
            # Use a constant, known, name and email.
72
            args["author_name"] = 'Launchpad Package Builder'
11315.1.2 by Tim Penhey
Use the configured noreply email address.
73
            args["author_email"] = config.canonical.noreply_from_address
11315.1.1 by Tim Penhey
Handle the case where there is not a preferred email set.
74
        else:
75
            args["author_name"] = requester.displayname
12001.3.18 by j.c.sackett
Updated tests.
76
            # We have to remove the security proxy here b/c there's not a
77
            # logged in entity, and anonymous email lookups aren't allowed.
78
            # Don't keep the naked requester around though.
79
            args["author_email"] = removeSecurityProxy(
80
                requester).preferredemail.email
10130.7.18 by Jelmer Vernooij
Further work on dispatchBuildToSlave.
81
        args["recipe_text"] = str(self.build.recipe.builder_recipe)
10130.7.21 by Jelmer Vernooij
Fix recipe builder tests.
82
        args['archive_purpose'] = self.build.archive.purpose.name
10130.7.27 by Jelmer Vernooij
Provide ogrecomponent.
83
        args["ogrecomponent"] = get_primary_current_component(
10130.7.34 by Jelmer Vernooij
review feedback from jono.
84
            self.build.archive, self.build.distroseries,
7675.700.6 by Paul Hummer
Fixed the tests
85
            None)
7675.502.26 by Jonathan Lange
Merge db-stable
86
        args['archives'] = get_sources_list_for_building(self.build,
7675.700.6 by Paul Hummer
Fixed the tests
87
            distroarchseries, None)
10795.2.2 by Julian Edwards
Ensure that recipe builds send a configured sources.list to the slave for an archive that contains the bzr-builder package
88
89
        # config.builddmaster.bzr_builder_sources_list can contain a
90
        # sources.list entry for an archive that will contain a
91
        # bzr-builder package that needs to be used to build this
92
        # recipe.
10795.2.4 by Julian Edwards
Fixes suggested by noodles' review
93
        try:
94
            extra_archive = config.builddmaster.bzr_builder_sources_list
95
        except AttributeError:
96
            extra_archive = None
97
10795.2.2 by Julian Edwards
Ensure that recipe builds send a configured sources.list to the slave for an archive that contains the bzr-builder package
98
        if extra_archive is not None:
99
            try:
100
                sources_line = extra_archive % (
101
                    {'series': self.build.distroseries.name})
102
                args['archives'].append(sources_line)
10795.2.4 by Julian Edwards
Fixes suggested by noodles' review
103
            except StandardError:
10795.2.2 by Julian Edwards
Ensure that recipe builds send a configured sources.list to the slave for an archive that contains the bzr-builder package
104
                # Someone messed up the config, don't add it.
7675.700.6 by Paul Hummer
Fixed the tests
105
                if logger:
106
                    logger.error(
107
                        "Exception processing bzr_builder_sources_list:\n%s"
108
                        % traceback.format_exc())
10795.2.4 by Julian Edwards
Fixes suggested by noodles' review
109
10739.2.4 by Aaron Bentley
Updates from review.
110
        args['distroseries_name'] = self.build.distroseries.name
10130.7.15 by Jelmer Vernooij
wip.
111
        return args
112
10130.7.2 by Jonathan Lange
Initial recipe builder behaviour stuff.
113
    def dispatchBuildToSlave(self, build_queue_id, logger):
10130.7.13 by Jelmer Vernooij
Make RecipeBuilder adapt IBuildSourcePackageFromRecipeJob.
114
        """See `IBuildFarmJobBehavior`."""
10130.7.15 by Jelmer Vernooij
wip.
115
10130.7.26 by Jelmer Vernooij
Move functionality for finding a distroarchseries by processor onto
116
        distroseries = self.build.distroseries
10130.7.15 by Jelmer Vernooij
wip.
117
        # Start the binary package build on the slave builder. First
118
        # we send the chroot.
10130.7.26 by Jelmer Vernooij
Move functionality for finding a distroarchseries by processor onto
119
        distroarchseries = distroseries.getDistroArchSeriesByProcessor(
120
            self._builder.processor)
121
        if distroarchseries is None:
10130.7.23 by Jelmer Vernooij
Remove i386-hardcoded bits.
122
            raise CannotBuild("Unable to find distroarchseries for %s in %s" %
123
                (self._builder.processor.name,
124
                self.build.distroseries.displayname))
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
125
        args = self._extraBuildArgs(distroarchseries, logger)
10130.7.21 by Jelmer Vernooij
Fix recipe builder tests.
126
        chroot = distroarchseries.getChroot()
127
        if chroot is None:
7675.502.26 by Jonathan Lange
Merge db-stable
128
            raise CannotBuild("Unable to find a chroot for %s" %
10130.7.21 by Jelmer Vernooij
Fix recipe builder tests.
129
                              distroarchseries.displayname)
11929.3.1 by Julian Edwards
Add extra default logging to help discover problems in the Deferred chain when dispatching.
130
        logger.info(
131
            "Sending chroot file for recipe build to %s" % self._builder.name)
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
132
        d = self._builder.slave.cacheFile(logger, chroot)
133
134
        def got_cache_file(ignored):
135
            # Generate a string which can be used to cross-check when obtaining
136
            # results so we know we are referring to the right database object in
137
            # subsequent runs.
138
            buildid = "%s-%s" % (self.build.id, build_queue_id)
139
            cookie = self.buildfarmjob.generateSlaveBuildCookie()
140
            chroot_sha1 = chroot.content.sha1
11929.3.1 by Julian Edwards
Add extra default logging to help discover problems in the Deferred chain when dispatching.
141
            logger.info(
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
142
                "Initiating build %s on %s" % (buildid, self._builder.url))
143
144
            return self._builder.slave.build(
145
                cookie, "sourcepackagerecipe", chroot_sha1, {}, args)
146
147
        def log_build_result((status, info)):
148
            message = """%s (%s):
149
            ***** RESULT *****
150
            %s
151
            %s: %s
152
            ******************
153
            """ % (
154
                self._builder.name,
155
                self._builder.url,
156
                args,
157
                status,
158
                info,
159
                )
160
            logger.info(message)
161
162
        return d.addCallback(got_cache_file).addCallback(log_build_result)
10130.7.15 by Jelmer Vernooij
wip.
163
164
    def verifyBuildRequest(self, logger):
165
        """Assert some pre-build checks.
166
167
        The build request is checked:
168
         * Virtualized builds can't build on a non-virtual builder
169
         * Ensure that we have a chroot
170
         * Ensure that the build pocket allows builds for the current
171
           distroseries state.
172
        """
173
        build = self.build
10604.4.2 by William Grant
Revert mistaken change.
174
        assert not (not self._builder.virtualized and build.is_virtualized), (
10855.1.1 by Aaron Bentley
Fix verifyBuildRequest to use valid attribute
175
            "Attempt to build virtual item on a non-virtual builder.")
10130.7.15 by Jelmer Vernooij
wip.
176
7675.467.4 by Jonathan Lange
Merge jelmer's branch, resolving conflicts.
177
        # This should already have been checked earlier, but just check again
10130.7.32 by Jelmer Vernooij
Factor out checks for allowing uploads to a pocket.
178
        # here in case of programmer errors.
10156.2.8 by Jelmer Vernooij
Remove more references to lp.archiveuploader.permission.
179
        reason = build.archive.checkUploadToPocket(
180
            build.distroseries, build.pocket)
10130.7.35 by Jelmer Vernooij
More review feedback from jono.
181
        assert reason is None, (
182
                "%s (%s) can not be built for pocket %s: invalid pocket due "
7675.502.26 by Jonathan Lange
Merge db-stable
183
                "to the series status of %s." %
10130.7.35 by Jelmer Vernooij
More review feedback from jono.
184
                    (build.title, build.id, build.pocket.name,
185
                     build.distroseries.name))
10130.8.2 by Michael Nelson
Moved _handleStatus_OK from IBuild to BuildBase as it's common between SPRecipe builds and binary builds. Also added slaveStatus() to the RecipeBuildBehavior.
186
10604.4.4 by William Grant
IBFJB.slaveStatus -> updateSlaveStatus; no longer returns the updated dict.
187
    def updateSlaveStatus(self, raw_slave_status, status):
10604.4.1 by William Grant
Move the common IBFJB.slaveStatus components into Builder.slaveStatus.
188
        """Parse the recipe build specific status info into the status dict.
10130.8.2 by Michael Nelson
Moved _handleStatus_OK from IBuild to BuildBase as it's common between SPRecipe builds and binary builds. Also added slaveStatus() to the RecipeBuildBehavior.
189
190
        This includes:
191
        * filemap => dictionary or None
192
        * dependencies => string or None
193
        """
10604.4.1 by William Grant
Move the common IBFJB.slaveStatus components into Builder.slaveStatus.
194
        build_status_with_files = (
195
            'BuildStatus.OK',
196
            'BuildStatus.PACKAGEFAIL',
197
            'BuildStatus.DEPFAIL',
198
            )
199
        if (status['builder_status'] == 'BuilderStatus.WAITING' and
200
            status['build_status'] in build_status_with_files):
201
            status['filemap'] = raw_slave_status[3]
202
            status['dependencies'] = raw_slave_status[4]