Merge lp:~cjwatson/launchpad/build-private-bpb-immediately into lp:launchpad
- build-private-bpb-immediately
- Merge into devel
Proposed by
Colin Watson
Status: | Rejected |
---|---|
Rejected by: | Colin Watson |
Proposed branch: | lp:~cjwatson/launchpad/build-private-bpb-immediately |
Merge into: | lp:launchpad |
Prerequisite: | lp:~cjwatson/launchpad/librarian-accept-macaroon |
Diff against target: |
276 lines (+60/-64) 4 files modified
lib/lp/buildmaster/tests/test_builder.py (+4/-4) lib/lp/soyuz/model/binarypackagebuild.py (+3/-27) lib/lp/soyuz/model/binarypackagebuildbehaviour.py (+12/-17) lib/lp/soyuz/tests/test_binarypackagebuildbehaviour.py (+41/-16) |
To merge this branch: | bzr merge lp:~cjwatson/launchpad/build-private-bpb-immediately |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Launchpad code reviewers | Pending | ||
Review via email: mp+345104@code.launchpad.net |
Commit message
Dispatch private BPBs immediately, using macaroon auth for source files.
Description of the change
The prerequisite branch must be deployed to the librarian before landing this.
I haven't yet tested this beyond what's in the test suite.
To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) wrote : | # |
Unmerged revisions
- 18632. By Colin Watson
-
Dispatch private BPBs immediately, using macaroon auth for source files.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/lp/buildmaster/tests/test_builder.py' | |||
2 | --- lib/lp/buildmaster/tests/test_builder.py 2018-01-10 10:45:24 +0000 | |||
3 | +++ lib/lp/buildmaster/tests/test_builder.py 2018-05-04 17:00:50 +0000 | |||
4 | @@ -401,13 +401,13 @@ | |||
5 | 401 | build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(next_job) | 401 | build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(next_job) |
6 | 402 | self.assertEqual('joesppa', build.archive.name) | 402 | self.assertEqual('joesppa', build.archive.name) |
7 | 403 | 403 | ||
11 | 404 | # If the source for the build is still pending, it won't be | 404 | # If the source for the build is still pending, it will still be |
12 | 405 | # dispatched because the builder has to fetch the source files | 405 | # dispatched: the builder will use macaroon authentication to fetch |
13 | 406 | # from the (password protected) repo area, not the librarian. | 406 | # the source files from the librarian. |
14 | 407 | pub = build.current_source_publication | 407 | pub = build.current_source_publication |
15 | 408 | pub.status = PackagePublishingStatus.PENDING | 408 | pub.status = PackagePublishingStatus.PENDING |
16 | 409 | candidate = removeSecurityProxy(self.builder4)._findBuildCandidate() | 409 | candidate = removeSecurityProxy(self.builder4)._findBuildCandidate() |
18 | 410 | self.assertNotEqual(next_job.id, candidate.id) | 410 | self.assertEqual(next_job.id, candidate.id) |
19 | 411 | 411 | ||
20 | 412 | 412 | ||
21 | 413 | class TestFindBuildCandidateDistroArchive(TestFindBuildCandidateBase): | 413 | class TestFindBuildCandidateDistroArchive(TestFindBuildCandidateBase): |
22 | 414 | 414 | ||
23 | === modified file 'lib/lp/soyuz/model/binarypackagebuild.py' | |||
24 | --- lib/lp/soyuz/model/binarypackagebuild.py 2018-05-04 17:00:50 +0000 | |||
25 | +++ lib/lp/soyuz/model/binarypackagebuild.py 2018-05-04 17:00:50 +0000 | |||
26 | @@ -87,10 +87,7 @@ | |||
27 | 87 | ) | 87 | ) |
28 | 88 | from lp.services.macaroons.interfaces import IMacaroonIssuer | 88 | from lp.services.macaroons.interfaces import IMacaroonIssuer |
29 | 89 | from lp.soyuz.adapters.buildarch import determine_architectures_to_build | 89 | from lp.soyuz.adapters.buildarch import determine_architectures_to_build |
34 | 90 | from lp.soyuz.enums import ( | 90 | from lp.soyuz.enums import ArchivePurpose |
31 | 91 | ArchivePurpose, | ||
32 | 92 | PackagePublishingStatus, | ||
33 | 93 | ) | ||
35 | 94 | from lp.soyuz.interfaces.archive import ( | 91 | from lp.soyuz.interfaces.archive import ( |
36 | 95 | InvalidExternalDependencies, | 92 | InvalidExternalDependencies, |
37 | 96 | validate_external_dependencies, | 93 | validate_external_dependencies, |
38 | @@ -1210,33 +1207,12 @@ | |||
39 | 1210 | @staticmethod | 1207 | @staticmethod |
40 | 1211 | def addCandidateSelectionCriteria(processor, virtualized): | 1208 | def addCandidateSelectionCriteria(processor, virtualized): |
41 | 1212 | """See `ISpecificBuildFarmJobSource`.""" | 1209 | """See `ISpecificBuildFarmJobSource`.""" |
42 | 1213 | private_statuses = ( | ||
43 | 1214 | PackagePublishingStatus.PUBLISHED, | ||
44 | 1215 | PackagePublishingStatus.SUPERSEDED, | ||
45 | 1216 | PackagePublishingStatus.DELETED, | ||
46 | 1217 | ) | ||
47 | 1218 | return """ | 1210 | return """ |
49 | 1219 | SELECT TRUE FROM Archive, BinaryPackageBuild, DistroArchSeries | 1211 | SELECT TRUE FROM BinaryPackageBuild |
50 | 1220 | WHERE | 1212 | WHERE |
51 | 1221 | BinaryPackageBuild.build_farm_job = BuildQueue.build_farm_job AND | 1213 | BinaryPackageBuild.build_farm_job = BuildQueue.build_farm_job AND |
52 | 1222 | BinaryPackageBuild.distro_arch_series = | ||
53 | 1223 | DistroArchSeries.id AND | ||
54 | 1224 | BinaryPackageBuild.archive = Archive.id AND | ||
55 | 1225 | ((Archive.private IS TRUE AND | ||
56 | 1226 | EXISTS ( | ||
57 | 1227 | SELECT SourcePackagePublishingHistory.id | ||
58 | 1228 | FROM SourcePackagePublishingHistory | ||
59 | 1229 | WHERE | ||
60 | 1230 | SourcePackagePublishingHistory.distroseries = | ||
61 | 1231 | DistroArchSeries.distroseries AND | ||
62 | 1232 | SourcePackagePublishingHistory.sourcepackagerelease = | ||
63 | 1233 | BinaryPackageBuild.source_package_release AND | ||
64 | 1234 | SourcePackagePublishingHistory.archive = Archive.id AND | ||
65 | 1235 | SourcePackagePublishingHistory.status IN %s)) | ||
66 | 1236 | OR | ||
67 | 1237 | archive.private IS FALSE) AND | ||
68 | 1238 | BinaryPackageBuild.status = %s | 1214 | BinaryPackageBuild.status = %s |
70 | 1239 | """ % sqlvalues(private_statuses, BuildStatus.NEEDSBUILD) | 1215 | """ % sqlvalues(BuildStatus.NEEDSBUILD) |
71 | 1240 | 1216 | ||
72 | 1241 | @staticmethod | 1217 | @staticmethod |
73 | 1242 | def postprocessCandidate(job, logger): | 1218 | def postprocessCandidate(job, logger): |
74 | 1243 | 1219 | ||
75 | === modified file 'lib/lp/soyuz/model/binarypackagebuildbehaviour.py' | |||
76 | --- lib/lp/soyuz/model/binarypackagebuildbehaviour.py 2018-03-01 17:36:31 +0000 | |||
77 | +++ lib/lp/soyuz/model/binarypackagebuildbehaviour.py 2018-05-04 17:00:50 +0000 | |||
78 | @@ -1,4 +1,4 @@ | |||
80 | 1 | # Copyright 2009-2017 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2018 Canonical Ltd. This software is licensed under the |
81 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
82 | 3 | 3 | ||
83 | 4 | """Builder behaviour for binary package builds.""" | 4 | """Builder behaviour for binary package builds.""" |
84 | @@ -10,7 +10,9 @@ | |||
85 | 10 | ] | 10 | ] |
86 | 11 | 11 | ||
87 | 12 | from twisted.internet import defer | 12 | from twisted.internet import defer |
88 | 13 | from zope.component import getUtility | ||
89 | 13 | from zope.interface import implementer | 14 | from zope.interface import implementer |
90 | 15 | from zope.security.proxy import removeSecurityProxy | ||
91 | 14 | 16 | ||
92 | 15 | from lp.buildmaster.interfaces.builder import CannotBuild | 17 | from lp.buildmaster.interfaces.builder import CannotBuild |
93 | 16 | from lp.buildmaster.interfaces.buildfarmjobbehaviour import ( | 18 | from lp.buildmaster.interfaces.buildfarmjobbehaviour import ( |
94 | @@ -20,16 +22,13 @@ | |||
95 | 20 | BuildFarmJobBehaviourBase, | 22 | BuildFarmJobBehaviourBase, |
96 | 21 | ) | 23 | ) |
97 | 22 | from lp.registry.interfaces.pocket import PackagePublishingPocket | 24 | from lp.registry.interfaces.pocket import PackagePublishingPocket |
102 | 23 | from lp.services.webapp import ( | 25 | from lp.services.macaroons.interfaces import IMacaroonIssuer |
103 | 24 | canonical_url, | 26 | from lp.services.webapp import canonical_url |
100 | 25 | urlappend, | ||
101 | 26 | ) | ||
104 | 27 | from lp.soyuz.adapters.archivedependencies import ( | 27 | from lp.soyuz.adapters.archivedependencies import ( |
105 | 28 | get_primary_current_component, | 28 | get_primary_current_component, |
106 | 29 | get_sources_list_for_building, | 29 | get_sources_list_for_building, |
107 | 30 | ) | 30 | ) |
108 | 31 | from lp.soyuz.enums import ArchivePurpose | 31 | from lp.soyuz.enums import ArchivePurpose |
109 | 32 | from lp.soyuz.model.publishing import makePoolPath | ||
110 | 33 | 32 | ||
111 | 34 | 33 | ||
112 | 35 | @implementer(IBuildFarmJobBehaviour) | 34 | @implementer(IBuildFarmJobBehaviour) |
113 | @@ -63,14 +62,9 @@ | |||
114 | 63 | # Build filemap structure with the files required in this build | 62 | # Build filemap structure with the files required in this build |
115 | 64 | # and send them to the slave. | 63 | # and send them to the slave. |
116 | 65 | if self.build.archive.private: | 64 | if self.build.archive.private: |
125 | 66 | # Builds in private archive may have restricted files that | 65 | issuer = getUtility(IMacaroonIssuer, 'binary-package-build') |
126 | 67 | # we can't obtain from the public librarian. Prepare a pool | 66 | password = removeSecurityProxy(issuer).issueMacaroon( |
127 | 68 | # URL from which to fetch them. | 67 | self.build).serialize() |
120 | 69 | pool_url = urlappend( | ||
121 | 70 | self.build.archive.archive_url, | ||
122 | 71 | makePoolPath( | ||
123 | 72 | self.build.source_package_release.sourcepackagename.name, | ||
124 | 73 | self.build.current_component.name)) | ||
128 | 74 | filemap = {} | 68 | filemap = {} |
129 | 75 | for source_file in self.build.source_package_release.files: | 69 | for source_file in self.build.source_package_release.files: |
130 | 76 | lfa = source_file.libraryfile | 70 | lfa = source_file.libraryfile |
131 | @@ -80,9 +74,10 @@ | |||
132 | 80 | else: | 74 | else: |
133 | 81 | filemap[lfa.filename] = { | 75 | filemap[lfa.filename] = { |
134 | 82 | 'sha1': lfa.content.sha1, | 76 | 'sha1': lfa.content.sha1, |
138 | 83 | 'url': urlappend(pool_url, lfa.filename), | 77 | 'url': lfa.https_url, |
139 | 84 | 'username': 'buildd', | 78 | 'username': '', |
140 | 85 | 'password': self.build.archive.buildd_secret} | 79 | 'password': password, |
141 | 80 | } | ||
142 | 86 | return filemap | 81 | return filemap |
143 | 87 | 82 | ||
144 | 88 | @defer.inlineCallbacks | 83 | @defer.inlineCallbacks |
145 | 89 | 84 | ||
146 | === modified file 'lib/lp/soyuz/tests/test_binarypackagebuildbehaviour.py' | |||
147 | --- lib/lp/soyuz/tests/test_binarypackagebuildbehaviour.py 2018-03-01 17:36:31 +0000 | |||
148 | +++ lib/lp/soyuz/tests/test_binarypackagebuildbehaviour.py 2018-05-04 17:00:50 +0000 | |||
149 | @@ -12,8 +12,15 @@ | |||
150 | 12 | import shutil | 12 | import shutil |
151 | 13 | import tempfile | 13 | import tempfile |
152 | 14 | 14 | ||
153 | 15 | from pymacaroons import Macaroon | ||
154 | 15 | from storm.store import Store | 16 | from storm.store import Store |
156 | 16 | from testtools.matchers import MatchesListwise | 17 | from testtools.matchers import ( |
157 | 18 | Contains, | ||
158 | 19 | Equals, | ||
159 | 20 | Matcher, | ||
160 | 21 | MatchesListwise, | ||
161 | 22 | Mismatch, | ||
162 | 23 | ) | ||
163 | 17 | from testtools.twistedsupport import AsynchronousDeferredRunTest | 24 | from testtools.twistedsupport import AsynchronousDeferredRunTest |
164 | 18 | import transaction | 25 | import transaction |
165 | 19 | from twisted.internet import defer | 26 | from twisted.internet import defer |
166 | @@ -21,7 +28,6 @@ | |||
167 | 21 | from zope.component import getUtility | 28 | from zope.component import getUtility |
168 | 22 | from zope.security.proxy import removeSecurityProxy | 29 | from zope.security.proxy import removeSecurityProxy |
169 | 23 | 30 | ||
170 | 24 | from lp.archivepublisher.diskpool import poolify | ||
171 | 25 | from lp.archivepublisher.interfaces.archivesigningkey import ( | 31 | from lp.archivepublisher.interfaces.archivesigningkey import ( |
172 | 26 | IArchiveSigningKey, | 32 | IArchiveSigningKey, |
173 | 27 | ) | 33 | ) |
174 | @@ -58,6 +64,7 @@ | |||
175 | 58 | from lp.services.config import config | 64 | from lp.services.config import config |
176 | 59 | from lp.services.librarian.interfaces import ILibraryFileAliasSet | 65 | from lp.services.librarian.interfaces import ILibraryFileAliasSet |
177 | 60 | from lp.services.log.logger import BufferLogger | 66 | from lp.services.log.logger import BufferLogger |
178 | 67 | from lp.services.macaroons.interfaces import IMacaroonIssuer | ||
179 | 61 | from lp.services.webapp import canonical_url | 68 | from lp.services.webapp import canonical_url |
180 | 62 | from lp.soyuz.adapters.archivedependencies import ( | 69 | from lp.soyuz.adapters.archivedependencies import ( |
181 | 63 | get_sources_list_for_building, | 70 | get_sources_list_for_building, |
182 | @@ -74,6 +81,26 @@ | |||
183 | 74 | from lp.testing.layers import LaunchpadZopelessLayer | 81 | from lp.testing.layers import LaunchpadZopelessLayer |
184 | 75 | 82 | ||
185 | 76 | 83 | ||
186 | 84 | class BinaryPackageBuildMacaroonVerifies(Matcher): | ||
187 | 85 | """Matches if a binary-package-build macaroon passes verification.""" | ||
188 | 86 | |||
189 | 87 | def __init__(self, build, lfa_id): | ||
190 | 88 | self.build = build | ||
191 | 89 | self.lfa_id = lfa_id | ||
192 | 90 | |||
193 | 91 | def match(self, macaroon_raw): | ||
194 | 92 | macaroon = Macaroon.deserialize(macaroon_raw) | ||
195 | 93 | expected_caveat = ( | ||
196 | 94 | "lp.binary-package-build %s" % removeSecurityProxy(self.build).id) | ||
197 | 95 | mismatch = Contains(expected_caveat).match( | ||
198 | 96 | [caveat.caveat_id for caveat in macaroon.caveats]) | ||
199 | 97 | if mismatch is not None: | ||
200 | 98 | return mismatch | ||
201 | 99 | issuer = getUtility(IMacaroonIssuer, "binary-package-build") | ||
202 | 100 | if not issuer.verifyMacaroon(macaroon, self.lfa_id): | ||
203 | 101 | return Mismatch("Macaroon does not verify") | ||
204 | 102 | |||
205 | 103 | |||
206 | 77 | class TestBinaryBuildPackageBehaviour(TestCaseWithFactory): | 104 | class TestBinaryBuildPackageBehaviour(TestCaseWithFactory): |
207 | 78 | """Tests for the BinaryPackageBuildBehaviour. | 105 | """Tests for the BinaryPackageBuildBehaviour. |
208 | 79 | 106 | ||
209 | @@ -98,7 +125,7 @@ | |||
210 | 98 | expected = yield self.makeExpectedInteraction( | 125 | expected = yield self.makeExpectedInteraction( |
211 | 99 | builder, build, chroot, archive, archive_purpose, component, | 126 | builder, build, chroot, archive, archive_purpose, component, |
212 | 100 | extra_uploads, filemap_names) | 127 | extra_uploads, filemap_names) |
214 | 101 | self.assertEqual(expected, call_log) | 128 | self.assertThat(call_log, MatchesListwise(expected)) |
215 | 102 | 129 | ||
216 | 103 | @defer.inlineCallbacks | 130 | @defer.inlineCallbacks |
217 | 104 | def makeExpectedInteraction(self, builder, build, chroot, archive, | 131 | def makeExpectedInteraction(self, builder, build, chroot, archive, |
218 | @@ -115,7 +142,7 @@ | |||
219 | 115 | builder. We specify this separately from the archive because | 142 | builder. We specify this separately from the archive because |
220 | 116 | sometimes the behaviour object has to give a different purpose | 143 | sometimes the behaviour object has to give a different purpose |
221 | 117 | in order to trick the slave into building correctly. | 144 | in order to trick the slave into building correctly. |
223 | 118 | :return: A list of the calls we expect to be made. | 145 | :return: A list of matchers for the calls we expect to be made. |
224 | 119 | """ | 146 | """ |
225 | 120 | das = build.distro_arch_series | 147 | das = build.distro_arch_series |
226 | 121 | ds_name = das.distroseries.name | 148 | ds_name = das.distroseries.name |
227 | @@ -131,8 +158,9 @@ | |||
228 | 131 | extra_uploads = [] | 158 | extra_uploads = [] |
229 | 132 | 159 | ||
230 | 133 | upload_logs = [ | 160 | upload_logs = [ |
233 | 134 | ('ensurepresent',) + upload | 161 | MatchesListwise((Equals('ensurepresent'),) + upload) |
234 | 135 | for upload in [(chroot.http_url, '', '')] + extra_uploads] | 162 | for upload in [(Equals(chroot.http_url), Equals(''), Equals(''))] + |
235 | 163 | extra_uploads] | ||
236 | 136 | 164 | ||
237 | 137 | extra_args = { | 165 | extra_args = { |
238 | 138 | 'arch_indep': arch_indep, | 166 | 'arch_indep': arch_indep, |
239 | @@ -149,8 +177,9 @@ | |||
240 | 149 | 'trusted_keys': trusted_keys, | 177 | 'trusted_keys': trusted_keys, |
241 | 150 | } | 178 | } |
242 | 151 | build_log = [ | 179 | build_log = [ |
245 | 152 | ('build', build.build_cookie, 'binarypackage', | 180 | MatchesListwise([Equals(arg) for arg in ( |
246 | 153 | chroot.content.sha1, filemap_names, extra_args)] | 181 | 'build', build.build_cookie, 'binarypackage', |
247 | 182 | chroot.content.sha1, filemap_names, extra_args)])] | ||
248 | 154 | result = upload_logs + build_log | 183 | result = upload_logs + build_log |
249 | 155 | defer.returnValue(result) | 184 | defer.returnValue(result) |
250 | 156 | 185 | ||
251 | @@ -244,13 +273,6 @@ | |||
252 | 244 | sprf = build.source_package_release.addFile( | 273 | sprf = build.source_package_release.addFile( |
253 | 245 | self.factory.makeLibraryFileAlias(db_only=True), | 274 | self.factory.makeLibraryFileAlias(db_only=True), |
254 | 246 | filetype=SourcePackageFileType.ORIG_TARBALL) | 275 | filetype=SourcePackageFileType.ORIG_TARBALL) |
255 | 247 | sprf_url = ( | ||
256 | 248 | 'http://private-ppa.launchpad.dev/%s/%s/ubuntu/pool/%s/%s' | ||
257 | 249 | % (archive.owner.name, archive.name, | ||
258 | 250 | poolify( | ||
259 | 251 | build.source_package_release.sourcepackagename.name, | ||
260 | 252 | 'main'), | ||
261 | 253 | sprf.libraryfile.filename)) | ||
262 | 254 | lf = self.factory.makeLibraryFileAlias() | 276 | lf = self.factory.makeLibraryFileAlias() |
263 | 255 | transaction.commit() | 277 | transaction.commit() |
264 | 256 | build.distro_arch_series.addOrUpdateChroot(lf) | 278 | build.distro_arch_series.addOrUpdateChroot(lf) |
265 | @@ -262,7 +284,10 @@ | |||
266 | 262 | interactor.getBuildBehaviour(bq, builder, slave), BufferLogger()) | 284 | interactor.getBuildBehaviour(bq, builder, slave), BufferLogger()) |
267 | 263 | yield self.assertExpectedInteraction( | 285 | yield self.assertExpectedInteraction( |
268 | 264 | slave.call_log, builder, build, lf, archive, ArchivePurpose.PPA, | 286 | slave.call_log, builder, build, lf, archive, ArchivePurpose.PPA, |
270 | 265 | extra_uploads=[(sprf_url, 'buildd', 'sekrit')], | 287 | extra_uploads=[( |
271 | 288 | Equals(sprf.libraryfile.https_url), Equals(''), | ||
272 | 289 | BinaryPackageBuildMacaroonVerifies( | ||
273 | 290 | build, sprf.libraryfile.id))], | ||
274 | 266 | filemap_names=[sprf.libraryfile.filename]) | 291 | filemap_names=[sprf.libraryfile.filename]) |
275 | 267 | 292 | ||
276 | 268 | @defer.inlineCallbacks | 293 | @defer.inlineCallbacks |
Superseded by https:/ /code.launchpad .net/~cjwatson/ launchpad/ +git/launchpad/ +merge/ 373741.