~launchpad-pqm/launchpad/devel

7675.391.6 by Muharem Hrnjadovic
Added 'buildpackagejob' interface/model classes.
1
# Copyright 2009 Canonical Ltd.  This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
3
4
__metaclass__ = type
10130.7.10 by Jonathan Lange
Add a model class for the job
5
__all__ = [
6
    'BuildPackageJob',
7
    ]
7675.391.6 by Muharem Hrnjadovic
Added 'buildpackagejob' interface/model classes.
8
9
7675.391.10 by Muharem Hrnjadovic
Lint fixes.
10
from datetime import datetime
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
11
7675.391.7 by Muharem Hrnjadovic
More refactoring in progress.
12
import pytz
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
13
from storm.locals import (
14
    Int,
15
    Reference,
16
    Storm,
17
    )
7675.452.6 by Muharem Hrnjadovic
"make lint" fixes
18
from zope.component import getUtility
10667.4.4 by Michael Nelson
Initial refactoring into a common PackageBuildFarmJobDelegate class.
19
from zope.interface import implements
7675.391.6 by Muharem Hrnjadovic
Added 'buildpackagejob' interface/model classes.
20
10085.2.1 by Muharem Hrnjadovic
imported the pieces of interest from the mega-branch (lp:~al-maisan/launchpad/ejdt-484819-ii)
21
from canonical.database.sqlbase import sqlvalues
11458.1.1 by Jelmer Vernooij
Move enums of buildmaster.
22
from lp.buildmaster.enums import BuildStatus
14550.1.1 by Steve Kowalik
Run format-imports over lib/lp and lib/canonical/launchpad
23
from lp.buildmaster.interfaces.builder import IBuilderSet
7675.687.46 by Michael Nelson
Created BuildFarmJobOldDerived and updated BRANCH.TODO to ensure they are later removed.
24
from lp.buildmaster.model.buildfarmjob import BuildFarmJobOldDerived
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
25
from lp.registry.interfaces.pocket import PackagePublishingPocket
11411.6.12 by Julian Edwards
Move PackagePublishingStatus/Priority
26
from lp.soyuz.enums import (
27
    ArchivePurpose,
28
    PackagePublishingStatus,
29
    )
10667.2.2 by Michael Nelson
Mass renaming of imports and references to IBuild/Build/IBuildSet
30
from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuildSet
13372.2.4 by Francis J. Lacoste
Refactor score modifiers into public constants.
31
from lp.soyuz.interfaces.buildpackagejob import (
32
    COPY_ARCHIVE_SCORE_PENALTY,
33
    IBuildPackageJob,
34
    PRIVATE_ARCHIVE_SCORE_BONUS,
35
    SCORE_BY_COMPONENT,
36
    SCORE_BY_POCKET,
37
    SCORE_BY_URGENCY,
38
    )
7675.687.43 by Michael Nelson
Cleaned up the interfaces so that the old in-memory BuildFarmJob interfaces stay intact until they are removed, rather than merging them with the new.
39
from lp.soyuz.model.buildfarmbuildjob import BuildFarmBuildJob
7675.391.6 by Muharem Hrnjadovic
Added 'buildpackagejob' interface/model classes.
40
41
7675.687.46 by Michael Nelson
Created BuildFarmJobOldDerived and updated BRANCH.TODO to ensure they are later removed.
42
class BuildPackageJob(BuildFarmJobOldDerived, Storm):
7675.391.6 by Muharem Hrnjadovic
Added 'buildpackagejob' interface/model classes.
43
    """See `IBuildPackageJob`."""
10130.1.3 by Jonathan Lange
Clean up a bit, deleting unnecessary code, PEP8
44
    implements(IBuildPackageJob)
10085.2.10 by Muharem Hrnjadovic
jml's review comments, round 3
45
7675.391.6 by Muharem Hrnjadovic
Added 'buildpackagejob' interface/model classes.
46
    __storm_table__ = 'buildpackagejob'
47
    id = Int(primary=True)
48
49
    job_id = Int(name='job', allow_none=False)
50
    job = Reference(job_id, 'Job.id')
51
52
    build_id = Int(name='build', allow_none=False)
10667.2.4 by Michael Nelson
Updated references to old 'Build' class.
53
    build = Reference(build_id, 'BinaryPackageBuild.id')
7675.391.7 by Muharem Hrnjadovic
More refactoring in progress.
54
10667.4.3 by Michael Nelson
Tweaks to get delegation working for both new jobs and those retrieved from
55
    def __init__(self, build, job):
10667.4.4 by Michael Nelson
Initial refactoring into a common PackageBuildFarmJobDelegate class.
56
        self.build, self.job = build, job
10667.4.3 by Michael Nelson
Tweaks to get delegation working for both new jobs and those retrieved from
57
        super(BuildPackageJob, self).__init__()
10667.4.1 by Michael Nelson
Initial delegation of BuildFarmJob.
58
7675.687.39 by Michael Nelson
Removed the dependency on PackageBuildDerived for the SPRBJob and BuildPackageJob classes.
59
    def _set_build_farm_job(self):
7675.693.3 by Michael Nelson
Changes from jelmer's review - comments.
60
        """Setup the IBuildFarmJob delegate.
7675.687.39 by Michael Nelson
Removed the dependency on PackageBuildDerived for the SPRBJob and BuildPackageJob classes.
61
62
        We override this to provide a delegate specific to package builds."""
7675.687.43 by Michael Nelson
Cleaned up the interfaces so that the old in-memory BuildFarmJob interfaces stay intact until they are removed, rather than merging them with the new.
63
        self.build_farm_job = BuildFarmBuildJob(self.build)
7675.687.39 by Michael Nelson
Removed the dependency on PackageBuildDerived for the SPRBJob and BuildPackageJob classes.
64
7675.391.7 by Muharem Hrnjadovic
More refactoring in progress.
65
    def score(self):
7675.390.6 by Muharem Hrnjadovic
Review comments, round 2.
66
        """See `IBuildPackageJob`."""
7675.391.7 by Muharem Hrnjadovic
More refactoring in progress.
67
        # Define a table we'll use to calculate the score based on the time
68
        # in the build queue.  The table is a sorted list of (upper time
69
        # limit in seconds, score) tuples.
70
        queue_time_scores = [
71
            (14400, 100),
72
            (7200, 50),
73
            (3600, 20),
74
            (1800, 15),
75
            (900, 10),
76
            (300, 5),
77
        ]
78
79
        # Please note: the score for language packs is to be zero because
80
        # they unduly delay the building of packages in the main component
81
        # otherwise.
7675.687.60 by Michael Nelson
Updated getBuildByArch() to match new tables.
82
        if self.build.source_package_release.section.name == 'translations':
13372.2.3 by Francis J. Lacoste
Make copy archive score follow the same rules than normal builds, but with a high penalty.
83
            return 0
84
85
        score = 0
86
87
        # Calculates the urgency-related part of the score.
13372.2.4 by Francis J. Lacoste
Refactor score modifiers into public constants.
88
        urgency = SCORE_BY_URGENCY[
89
            self.build.source_package_release.urgency]
13372.2.3 by Francis J. Lacoste
Make copy archive score follow the same rules than normal builds, but with a high penalty.
90
        score += urgency
91
92
        # Calculates the pocket-related part of the score.
13372.2.4 by Francis J. Lacoste
Refactor score modifiers into public constants.
93
        score_pocket = SCORE_BY_POCKET[self.build.pocket]
13372.2.3 by Francis J. Lacoste
Make copy archive score follow the same rules than normal builds, but with a high penalty.
94
        score += score_pocket
95
96
        # Calculates the component-related part of the score.
13372.2.4 by Francis J. Lacoste
Refactor score modifiers into public constants.
97
        score += SCORE_BY_COMPONENT.get(
13372.2.3 by Francis J. Lacoste
Make copy archive score follow the same rules than normal builds, but with a high penalty.
98
            self.build.current_component.name, 0)
99
100
        # Calculates the build queue time component of the score.
101
        right_now = datetime.now(pytz.timezone('UTC'))
102
        eta = right_now - self.job.date_created
103
        for limit, dep_score in queue_time_scores:
104
            if eta.seconds > limit:
105
                score += dep_score
106
                break
107
108
        # Private builds get uber score.
109
        if self.build.archive.private:
13372.2.4 by Francis J. Lacoste
Refactor score modifiers into public constants.
110
            score += PRIVATE_ARCHIVE_SCORE_BONUS
111
112
        if self.build.archive.is_copy:
113
            score -= COPY_ARCHIVE_SCORE_PENALTY
13372.2.3 by Francis J. Lacoste
Make copy archive score follow the same rules than normal builds, but with a high penalty.
114
115
        # Lastly, apply the archive score delta.  This is to boost
116
        # or retard build scores for any build in a particular
117
        # archive.
118
        score += self.build.archive.relative_build_score
119
7675.391.10 by Muharem Hrnjadovic
Lint fixes.
120
        return score
7675.391.7 by Muharem Hrnjadovic
More refactoring in progress.
121
122
    def getLogFileName(self):
7675.390.6 by Muharem Hrnjadovic
Review comments, round 2.
123
        """See `IBuildPackageJob`."""
7675.687.60 by Michael Nelson
Updated getBuildByArch() to match new tables.
124
        sourcename = self.build.source_package_release.name
125
        version = self.build.source_package_release.version
7675.391.7 by Muharem Hrnjadovic
More refactoring in progress.
126
        # we rely on previous storage of current buildstate
127
        # in the state handling methods.
7675.687.65 by Michael Nelson
Continuing to get test_binarypackagebuild module to pass.
128
        state = self.build.status.name
7675.391.7 by Muharem Hrnjadovic
More refactoring in progress.
129
7675.687.65 by Michael Nelson
Continuing to get test_binarypackagebuild module to pass.
130
        dar = self.build.distro_arch_series
7675.391.7 by Muharem Hrnjadovic
More refactoring in progress.
131
        distroname = dar.distroseries.distribution.name
132
        distroseriesname = dar.distroseries.name
133
        archname = dar.architecturetag
134
135
        # logfilename format:
136
        # buildlog_<DISTRIBUTION>_<DISTROSeries>_<ARCHITECTURE>_\
137
        # <SOURCENAME>_<SOURCEVERSION>_<BUILDSTATE>.txt
138
        # as:
139
        # buildlog_ubuntu_dapper_i386_foo_1.0-ubuntu0_FULLYBUILT.txt
140
        # it fix request from bug # 30617
141
        return ('buildlog_%s-%s-%s.%s_%s_%s.txt' % (
10130.1.3 by Jonathan Lange
Clean up a bit, deleting unnecessary code, PEP8
142
            distroname, distroseriesname, archname, sourcename, version,
143
            state))
7675.391.23 by Muharem Hrnjadovic
Fixed more tests.
144
145
    def getName(self):
7675.390.6 by Muharem Hrnjadovic
Review comments, round 2.
146
        """See `IBuildPackageJob`."""
7675.687.60 by Michael Nelson
Updated getBuildByArch() to match new tables.
147
        return self.build.source_package_release.name
7675.391.27 by Muharem Hrnjadovic
More fixes.
148
10085.2.1 by Muharem Hrnjadovic
imported the pieces of interest from the mega-branch (lp:~al-maisan/launchpad/ejdt-484819-ii)
149
    @property
150
    def processor(self):
151
        """See `IBuildFarmJob`."""
152
        return self.build.processor
153
154
    @property
155
    def virtualized(self):
156
        """See `IBuildFarmJob`."""
157
        return self.build.is_virtualized
7675.452.1 by Muharem Hrnjadovic
imported old development branch
158
159
    @staticmethod
7675.452.10 by Muharem Hrnjadovic
jtv's review comments
160
    def addCandidateSelectionCriteria(processor, virtualized):
10667.4.8 by Michael Nelson
Merged IBuildFarmCandidateJobSelection into IBuildFarmJob.
161
        """See `IBuildFarmJob`."""
7675.452.1 by Muharem Hrnjadovic
imported old development branch
162
        private_statuses = (
163
            PackagePublishingStatus.PUBLISHED,
164
            PackagePublishingStatus.SUPERSEDED,
165
            PackagePublishingStatus.DELETED,
166
            )
7675.464.1 by Muharem Hrnjadovic
imported fix for candidate job selection
167
        sub_query = """
7675.687.92 by Michael Nelson
Changes for buildd-dispatching.txt
168
            SELECT TRUE FROM Archive, BinaryPackageBuild, BuildPackageJob,
169
                             PackageBuild, BuildFarmJob, DistroArchSeries
7675.464.1 by Muharem Hrnjadovic
imported fix for candidate job selection
170
            WHERE
7675.502.26 by Jonathan Lange
Merge db-stable
171
            BuildPackageJob.job = Job.id AND
7675.687.92 by Michael Nelson
Changes for buildd-dispatching.txt
172
            BuildPackageJob.build = BinaryPackageBuild.id AND
173
            BinaryPackageBuild.distro_arch_series =
174
                DistroArchSeries.id AND
175
            BinaryPackageBuild.package_build = PackageBuild.id AND
176
            PackageBuild.archive = Archive.id AND
7675.452.1 by Muharem Hrnjadovic
imported old development branch
177
            ((Archive.private IS TRUE AND
178
              EXISTS (
179
                  SELECT SourcePackagePublishingHistory.id
180
                  FROM SourcePackagePublishingHistory
181
                  WHERE
182
                      SourcePackagePublishingHistory.distroseries =
183
                         DistroArchSeries.distroseries AND
184
                      SourcePackagePublishingHistory.sourcepackagerelease =
7675.687.92 by Michael Nelson
Changes for buildd-dispatching.txt
185
                         BinaryPackageBuild.source_package_release AND
7675.452.1 by Muharem Hrnjadovic
imported old development branch
186
                      SourcePackagePublishingHistory.archive = Archive.id AND
187
                      SourcePackagePublishingHistory.status IN %s))
188
              OR
189
              archive.private IS FALSE) AND
7675.687.92 by Michael Nelson
Changes for buildd-dispatching.txt
190
            PackageBuild.build_farm_job = BuildFarmJob.id AND
191
            BuildFarmJob.status = %s
7675.452.1 by Muharem Hrnjadovic
imported old development branch
192
        """ % sqlvalues(private_statuses, BuildStatus.NEEDSBUILD)
193
194
        # Ensure that if BUILDING builds exist for the same
195
        # public ppa archive and architecture and another would not
196
        # leave at least 20% of them free, then we don't consider
197
        # another as a candidate.
198
        #
199
        # This clause selects the count of currently building builds on
200
        # the arch in question, then adds one to that total before
201
        # deriving a percentage of the total available builders on that
202
        # arch.  It then makes sure that percentage is under 80.
203
        #
204
        # The extra clause is only used if the number of available
205
        # builders is greater than one, or nothing would get dispatched
206
        # at all.
11983.2.3 by Julian Edwards
Fix fallout from builderok turning into _builderok on the model
207
        num_arch_builders = getUtility(IBuilderSet).getBuildersForQueue(
208
            processor, virtualized).count()
7675.452.1 by Muharem Hrnjadovic
imported old development branch
209
        if num_arch_builders > 1:
7675.464.1 by Muharem Hrnjadovic
imported fix for candidate job selection
210
            sub_query += """
10977.4.1 by Julian Edwards
Replace the query that limits binary package builds to 80% usage with a faster one.
211
            AND Archive.id NOT IN (
212
                SELECT Archive.id
213
                FROM PackageBuild, BuildFarmJob, Archive,
214
                    BinaryPackageBuild, DistroArchSeries
215
                WHERE
216
                    PackageBuild.build_farm_job = BuildFarmJob.id
217
                    AND BinaryPackageBuild.package_build = PackageBuild.id
218
                    AND BinaryPackageBuild.distro_arch_series
219
                        = DistroArchSeries.id
220
                    AND DistroArchSeries.processorfamily = %s
221
                    AND BuildFarmJob.status = %s
222
                    AND PackageBuild.archive = Archive.id
223
                    AND Archive.purpose = %s
224
                    AND Archive.private IS FALSE
225
                GROUP BY Archive.id
226
                HAVING (
227
                    (count(*)+1) * 100.0 / %s
228
                    ) >= 80
229
                )
7675.452.1 by Muharem Hrnjadovic
imported old development branch
230
            """ % sqlvalues(
10977.4.1 by Julian Edwards
Replace the query that limits binary package builds to 80% usage with a faster one.
231
                processor.family, BuildStatus.BUILDING,
232
                ArchivePurpose.PPA, num_arch_builders)
7675.452.1 by Muharem Hrnjadovic
imported old development branch
233
7675.464.1 by Muharem Hrnjadovic
imported fix for candidate job selection
234
        return sub_query
7675.452.1 by Muharem Hrnjadovic
imported old development branch
235
236
    @staticmethod
7675.452.10 by Muharem Hrnjadovic
jtv's review comments
237
    def postprocessCandidate(job, logger):
10667.4.8 by Michael Nelson
Merged IBuildFarmCandidateJobSelection into IBuildFarmJob.
238
        """See `IBuildFarmJob`."""
7675.452.6 by Muharem Hrnjadovic
"make lint" fixes
239
        # Mark build records targeted to old source versions as SUPERSEDED
240
        # and build records target to SECURITY pocket as FAILEDTOBUILD.
241
        # Builds in those situation should not be built because they will
242
        # be wasting build-time, the former case already has a newer source
243
        # and the latter could not be built in DAK.
10667.2.2 by Michael Nelson
Mass renaming of imports and references to IBuild/Build/IBuildSet
244
        build_set = getUtility(IBinaryPackageBuildSet)
7675.452.6 by Muharem Hrnjadovic
"make lint" fixes
245
246
        build = build_set.getByQueueEntry(job)
247
        if build.pocket == PackagePublishingPocket.SECURITY:
248
            # We never build anything in the security pocket.
249
            logger.debug(
250
                "Build %s FAILEDTOBUILD, queue item %s REMOVED"
251
                % (build.id, job.id))
7675.687.92 by Michael Nelson
Changes for buildd-dispatching.txt
252
            build.status = BuildStatus.FAILEDTOBUILD
7675.452.6 by Muharem Hrnjadovic
"make lint" fixes
253
            job.destroySelf()
254
            return False
255
256
        publication = build.current_source_publication
257
        if publication is None:
258
            # The build should be superseded if it no longer has a
259
            # current publishing record.
260
            logger.debug(
261
                "Build %s SUPERSEDED, queue item %s REMOVED"
262
                % (build.id, job.id))
7675.687.92 by Michael Nelson
Changes for buildd-dispatching.txt
263
            build.status = BuildStatus.SUPERSEDED
7675.452.6 by Muharem Hrnjadovic
"make lint" fixes
264
            job.destroySelf()
265
            return False
266
7675.452.1 by Muharem Hrnjadovic
imported old development branch
267
        return True