Merge lp:~cjwatson/launchpad-buildd/proxy-configs into lp:launchpad-buildd
- proxy-configs
- Merge into trunk
Proposed by
Colin Watson
Status: | Merged |
---|---|
Merged at revision: | 382 |
Proposed branch: | lp:~cjwatson/launchpad-buildd/proxy-configs |
Merge into: | lp:launchpad-buildd |
Diff against target: |
685 lines (+293/-23) 17 files modified
debian/changelog (+7/-0) debian/control (+3/-0) lpbuildd/debian.py (+13/-2) lpbuildd/livefs.py (+12/-1) lpbuildd/snap.py (+11/-1) lpbuildd/target/apt.py (+13/-1) lpbuildd/target/build_livefs.py (+5/-2) lpbuildd/target/build_snap.py (+5/-2) lpbuildd/target/snapstore.py (+42/-0) lpbuildd/target/tests/test_apt.py (+22/-1) lpbuildd/target/tests/test_build_livefs.py (+39/-2) lpbuildd/target/tests/test_build_snap.py (+41/-4) lpbuildd/tests/fakebuilder.py (+22/-2) lpbuildd/tests/test_debian.py (+31/-1) lpbuildd/tests/test_livefs.py (+13/-2) lpbuildd/tests/test_snap.py (+10/-1) setup.py (+4/-1) |
To merge this branch: | bzr merge lp:~cjwatson/launchpad-buildd/proxy-configs |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tom Wardill (community) | Approve | ||
Review via email: mp+362332@code.launchpad.net |
Commit message
Allow configuring APT or snap store proxies via a new [proxy] configuration file section.
Description of the change
This makes testing builds behind a slow connection 90% less annoying.
While python-requests and python-six are new direct dependencies in this branch, they were already indirect dependencies.
To post a comment you must log in.
Revision history for this message
Tom Wardill (twom) : | # |
review:
Approve
- 359. By Colin Watson
-
Simplify snap_store_
set_proxy using the X-Assertion- Store-Id header. - 360. By Colin Watson
-
Merge trunk.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'debian/changelog' | |||
2 | --- debian/changelog 2019-05-23 16:23:54 +0000 | |||
3 | +++ debian/changelog 2019-06-05 14:11:48 +0000 | |||
4 | @@ -1,3 +1,10 @@ | |||
5 | 1 | launchpad-buildd (175) UNRELEASED; urgency=medium | ||
6 | 2 | |||
7 | 3 | * Allow configuring APT or snap store proxies via a new [proxy] | ||
8 | 4 | configuration file section. | ||
9 | 5 | |||
10 | 6 | -- Colin Watson <cjwatson@ubuntu.com> Wed, 05 Jun 2019 15:06:54 +0100 | ||
11 | 7 | |||
12 | 1 | launchpad-buildd (174) xenial; urgency=medium | 8 | launchpad-buildd (174) xenial; urgency=medium |
13 | 2 | 9 | ||
14 | 3 | * Fix a missing piece from the changes in launchpad-buildd 168 that were | 10 | * Fix a missing piece from the changes in launchpad-buildd 168 that were |
15 | 4 | 11 | ||
16 | === modified file 'debian/control' | |||
17 | --- debian/control 2018-06-07 16:23:18 +0000 | |||
18 | +++ debian/control 2019-06-05 14:11:48 +0000 | |||
19 | @@ -17,7 +17,10 @@ | |||
20 | 17 | python-mock, | 17 | python-mock, |
21 | 18 | python-netaddr, | 18 | python-netaddr, |
22 | 19 | python-pylxd, | 19 | python-pylxd, |
23 | 20 | python-requests, | ||
24 | 21 | python-responses, | ||
25 | 20 | python-setuptools, | 22 | python-setuptools, |
26 | 23 | python-six, | ||
27 | 21 | python-systemfixtures, | 24 | python-systemfixtures, |
28 | 22 | python-testtools, | 25 | python-testtools, |
29 | 23 | python-twisted, | 26 | python-twisted, |
30 | 24 | 27 | ||
31 | === modified file 'lpbuildd/debian.py' | |||
32 | --- lpbuildd/debian.py 2019-02-12 10:35:12 +0000 | |||
33 | +++ lpbuildd/debian.py 2019-06-05 14:11:48 +0000 | |||
34 | @@ -1,4 +1,4 @@ | |||
36 | 1 | # Copyright 2009-2018 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2019 Canonical Ltd. This software is licensed under the |
37 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
38 | 3 | 3 | ||
39 | 4 | # Authors: Daniel Silverstone <daniel.silverstone@canonical.com> | 4 | # Authors: Daniel Silverstone <daniel.silverstone@canonical.com> |
40 | @@ -11,6 +11,10 @@ | |||
41 | 11 | import re | 11 | import re |
42 | 12 | import signal | 12 | import signal |
43 | 13 | 13 | ||
44 | 14 | from six.moves.configparser import ( | ||
45 | 15 | NoOptionError, | ||
46 | 16 | NoSectionError, | ||
47 | 17 | ) | ||
48 | 14 | from twisted.internet import ( | 18 | from twisted.internet import ( |
49 | 15 | defer, | 19 | defer, |
50 | 16 | threads, | 20 | threads, |
51 | @@ -59,7 +63,14 @@ | |||
52 | 59 | 63 | ||
53 | 60 | Mainly used for PPA builds. | 64 | Mainly used for PPA builds. |
54 | 61 | """ | 65 | """ |
56 | 62 | self.runTargetSubProcess("override-sources-list", *self.sources_list) | 66 | args = [] |
57 | 67 | try: | ||
58 | 68 | apt_proxy_url = self._builder._config.get("proxy", "apt") | ||
59 | 69 | args.extend(["--apt-proxy-url", apt_proxy_url]) | ||
60 | 70 | except (NoSectionError, NoOptionError): | ||
61 | 71 | pass | ||
62 | 72 | args.extend(self.sources_list) | ||
63 | 73 | self.runTargetSubProcess("override-sources-list", *args) | ||
64 | 63 | 74 | ||
65 | 64 | def doTrustedKeys(self): | 75 | def doTrustedKeys(self): |
66 | 65 | """Add trusted keys.""" | 76 | """Add trusted keys.""" |
67 | 66 | 77 | ||
68 | === modified file 'lpbuildd/livefs.py' | |||
69 | --- lpbuildd/livefs.py 2019-02-12 10:35:12 +0000 | |||
70 | +++ lpbuildd/livefs.py 2019-06-05 14:11:48 +0000 | |||
71 | @@ -1,10 +1,15 @@ | |||
73 | 1 | # Copyright 2013-2018 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2013-2019 Canonical Ltd. This software is licensed under the |
74 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
75 | 3 | 3 | ||
76 | 4 | __metaclass__ = type | 4 | __metaclass__ = type |
77 | 5 | 5 | ||
78 | 6 | import os | 6 | import os |
79 | 7 | 7 | ||
80 | 8 | from six.moves.configparser import ( | ||
81 | 9 | NoOptionError, | ||
82 | 10 | NoSectionError, | ||
83 | 11 | ) | ||
84 | 12 | |||
85 | 8 | from lpbuildd.debian import ( | 13 | from lpbuildd.debian import ( |
86 | 9 | DebianBuildManager, | 14 | DebianBuildManager, |
87 | 10 | DebianBuildState, | 15 | DebianBuildState, |
88 | @@ -71,6 +76,12 @@ | |||
89 | 71 | args.extend(["--repo-snapshot-stamp", self.repo_snapshot_stamp]) | 76 | args.extend(["--repo-snapshot-stamp", self.repo_snapshot_stamp]) |
90 | 72 | if self.cohort_key: | 77 | if self.cohort_key: |
91 | 73 | args.extend(["--cohort-key", self.cohort_key]) | 78 | args.extend(["--cohort-key", self.cohort_key]) |
92 | 79 | try: | ||
93 | 80 | snap_store_proxy_url = self._builder._config.get( | ||
94 | 81 | "proxy", "snapstore") | ||
95 | 82 | args.extend(["--snap-store-proxy-url", snap_store_proxy_url]) | ||
96 | 83 | except (NoSectionError, NoOptionError): | ||
97 | 84 | pass | ||
98 | 74 | if self.debug: | 85 | if self.debug: |
99 | 75 | args.append("--debug") | 86 | args.append("--debug") |
100 | 76 | self.runTargetSubProcess("buildlivefs", *args) | 87 | self.runTargetSubProcess("buildlivefs", *args) |
101 | 77 | 88 | ||
102 | === modified file 'lpbuildd/snap.py' | |||
103 | --- lpbuildd/snap.py 2019-05-22 17:59:14 +0000 | |||
104 | +++ lpbuildd/snap.py 2019-06-05 14:11:48 +0000 | |||
105 | @@ -1,4 +1,4 @@ | |||
107 | 1 | # Copyright 2015-2018 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2015-2019 Canonical Ltd. This software is licensed under the |
108 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
109 | 3 | 3 | ||
110 | 4 | from __future__ import print_function | 4 | from __future__ import print_function |
111 | @@ -29,6 +29,10 @@ | |||
112 | 29 | ) | 29 | ) |
113 | 30 | from urlparse import urlparse | 30 | from urlparse import urlparse |
114 | 31 | 31 | ||
115 | 32 | from six.moves.configparser import ( | ||
116 | 33 | NoOptionError, | ||
117 | 34 | NoSectionError, | ||
118 | 35 | ) | ||
119 | 32 | from twisted.application import strports | 36 | from twisted.application import strports |
120 | 33 | from twisted.internet import reactor | 37 | from twisted.internet import reactor |
121 | 34 | from twisted.internet.interfaces import IHalfCloseableProtocol | 38 | from twisted.internet.interfaces import IHalfCloseableProtocol |
122 | @@ -351,6 +355,12 @@ | |||
123 | 351 | args.append("--build-source-tarball") | 355 | args.append("--build-source-tarball") |
124 | 352 | if self.private: | 356 | if self.private: |
125 | 353 | args.append("--private") | 357 | args.append("--private") |
126 | 358 | try: | ||
127 | 359 | snap_store_proxy_url = self._builder._config.get( | ||
128 | 360 | "proxy", "snapstore") | ||
129 | 361 | args.extend(["--snap-store-proxy-url", snap_store_proxy_url]) | ||
130 | 362 | except (NoSectionError, NoOptionError): | ||
131 | 363 | pass | ||
132 | 354 | args.append(self.name) | 364 | args.append(self.name) |
133 | 355 | self.runTargetSubProcess("buildsnap", *args) | 365 | self.runTargetSubProcess("buildsnap", *args) |
134 | 356 | 366 | ||
135 | 357 | 367 | ||
136 | === modified file 'lpbuildd/target/apt.py' | |||
137 | --- lpbuildd/target/apt.py 2017-08-22 15:55:44 +0000 | |||
138 | +++ lpbuildd/target/apt.py 2019-06-05 14:11:48 +0000 | |||
139 | @@ -1,4 +1,4 @@ | |||
141 | 1 | # Copyright 2009-2017 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2019 Canonical Ltd. This software is licensed under the |
142 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
143 | 3 | 3 | ||
144 | 4 | from __future__ import print_function | 4 | from __future__ import print_function |
145 | @@ -26,6 +26,8 @@ | |||
146 | 26 | def add_arguments(cls, parser): | 26 | def add_arguments(cls, parser): |
147 | 27 | super(OverrideSourcesList, cls).add_arguments(parser) | 27 | super(OverrideSourcesList, cls).add_arguments(parser) |
148 | 28 | parser.add_argument( | 28 | parser.add_argument( |
149 | 29 | "--apt-proxy-url", metavar="URL", help="APT proxy URL") | ||
150 | 30 | parser.add_argument( | ||
151 | 29 | "archives", metavar="ARCHIVE", nargs="+", | 31 | "archives", metavar="ARCHIVE", nargs="+", |
152 | 30 | help="sources.list lines") | 32 | help="sources.list lines") |
153 | 31 | 33 | ||
154 | @@ -37,6 +39,16 @@ | |||
155 | 37 | sources_list.flush() | 39 | sources_list.flush() |
156 | 38 | os.fchmod(sources_list.fileno(), 0o644) | 40 | os.fchmod(sources_list.fileno(), 0o644) |
157 | 39 | self.backend.copy_in(sources_list.name, "/etc/apt/sources.list") | 41 | self.backend.copy_in(sources_list.name, "/etc/apt/sources.list") |
158 | 42 | if self.args.apt_proxy_url is not None: | ||
159 | 43 | with tempfile.NamedTemporaryFile() as apt_proxy_conf: | ||
160 | 44 | print( | ||
161 | 45 | 'Acquire::http::Proxy "{}";'.format( | ||
162 | 46 | self.args.apt_proxy_url), | ||
163 | 47 | file=apt_proxy_conf) | ||
164 | 48 | apt_proxy_conf.flush() | ||
165 | 49 | os.fchmod(apt_proxy_conf.fileno(), 0o644) | ||
166 | 50 | self.backend.copy_in( | ||
167 | 51 | apt_proxy_conf.name, "/etc/apt/apt.conf.d/99proxy") | ||
168 | 40 | return 0 | 52 | return 0 |
169 | 41 | 53 | ||
170 | 42 | 54 | ||
171 | 43 | 55 | ||
172 | === modified file 'lpbuildd/target/build_livefs.py' | |||
173 | --- lpbuildd/target/build_livefs.py 2019-01-28 13:10:24 +0000 | |||
174 | +++ lpbuildd/target/build_livefs.py 2019-06-05 14:11:48 +0000 | |||
175 | @@ -1,4 +1,4 @@ | |||
177 | 1 | # Copyright 2013-2017 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2013-2019 Canonical Ltd. This software is licensed under the |
178 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
179 | 3 | 3 | ||
180 | 4 | from __future__ import print_function | 4 | from __future__ import print_function |
181 | @@ -10,6 +10,7 @@ | |||
182 | 10 | import os | 10 | import os |
183 | 11 | 11 | ||
184 | 12 | from lpbuildd.target.operation import Operation | 12 | from lpbuildd.target.operation import Operation |
185 | 13 | from lpbuildd.target.snapstore import SnapStoreOperationMixin | ||
186 | 13 | 14 | ||
187 | 14 | 15 | ||
188 | 15 | RETCODE_FAILURE_INSTALL = 200 | 16 | RETCODE_FAILURE_INSTALL = 200 |
189 | @@ -29,7 +30,7 @@ | |||
190 | 29 | return os.path.join(os.environ["HOME"], "build-" + build_id, *extra) | 30 | return os.path.join(os.environ["HOME"], "build-" + build_id, *extra) |
191 | 30 | 31 | ||
192 | 31 | 32 | ||
194 | 32 | class BuildLiveFS(Operation): | 33 | class BuildLiveFS(SnapStoreOperationMixin, Operation): |
195 | 33 | 34 | ||
196 | 34 | description = "Build a live file system." | 35 | description = "Build a live file system." |
197 | 35 | 36 | ||
198 | @@ -94,6 +95,8 @@ | |||
199 | 94 | if self.backend.is_package_available(dep): | 95 | if self.backend.is_package_available(dep): |
200 | 95 | deps.append(dep) | 96 | deps.append(dep) |
201 | 96 | self.backend.run(["apt-get", "-y", "install"] + deps) | 97 | self.backend.run(["apt-get", "-y", "install"] + deps) |
202 | 98 | if self.args.backend in ("lxd", "fake"): | ||
203 | 99 | self.snap_store_set_proxy() | ||
204 | 97 | if self.args.arch == "i386": | 100 | if self.args.arch == "i386": |
205 | 98 | self.backend.run([ | 101 | self.backend.run([ |
206 | 99 | "apt-get", "-y", "--no-install-recommends", "install", | 102 | "apt-get", "-y", "--no-install-recommends", "install", |
207 | 100 | 103 | ||
208 | === modified file 'lpbuildd/target/build_snap.py' | |||
209 | --- lpbuildd/target/build_snap.py 2019-05-08 14:52:28 +0000 | |||
210 | +++ lpbuildd/target/build_snap.py 2019-06-05 14:11:48 +0000 | |||
211 | @@ -1,4 +1,4 @@ | |||
213 | 1 | # Copyright 2015-2017 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2015-2019 Canonical Ltd. This software is licensed under the |
214 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
215 | 3 | 3 | ||
216 | 4 | from __future__ import print_function | 4 | from __future__ import print_function |
217 | @@ -19,6 +19,7 @@ | |||
218 | 19 | from urlparse import urlparse | 19 | from urlparse import urlparse |
219 | 20 | 20 | ||
220 | 21 | from lpbuildd.target.operation import Operation | 21 | from lpbuildd.target.operation import Operation |
221 | 22 | from lpbuildd.target.snapstore import SnapStoreOperationMixin | ||
222 | 22 | from lpbuildd.target.vcs import VCSOperationMixin | 23 | from lpbuildd.target.vcs import VCSOperationMixin |
223 | 23 | 24 | ||
224 | 24 | 25 | ||
225 | @@ -47,7 +48,7 @@ | |||
226 | 47 | getattr(namespace, self.dest)[snap] = channel | 48 | getattr(namespace, self.dest)[snap] = channel |
227 | 48 | 49 | ||
228 | 49 | 50 | ||
230 | 50 | class BuildSnap(VCSOperationMixin, Operation): | 51 | class BuildSnap(VCSOperationMixin, SnapStoreOperationMixin, Operation): |
231 | 51 | 52 | ||
232 | 52 | description = "Build a snap." | 53 | description = "Build a snap." |
233 | 53 | 54 | ||
234 | @@ -154,6 +155,8 @@ | |||
235 | 154 | else: | 155 | else: |
236 | 155 | deps.append("snapcraft") | 156 | deps.append("snapcraft") |
237 | 156 | self.backend.run(["apt-get", "-y", "install"] + deps) | 157 | self.backend.run(["apt-get", "-y", "install"] + deps) |
238 | 158 | if self.args.backend in ("lxd", "fake"): | ||
239 | 159 | self.snap_store_set_proxy() | ||
240 | 157 | for snap_name in self.core_snap_names: | 160 | for snap_name in self.core_snap_names: |
241 | 158 | if snap_name in self.args.channels: | 161 | if snap_name in self.args.channels: |
242 | 159 | self.backend.run( | 162 | self.backend.run( |
243 | 160 | 163 | ||
244 | === added file 'lpbuildd/target/snapstore.py' | |||
245 | --- lpbuildd/target/snapstore.py 1970-01-01 00:00:00 +0000 | |||
246 | +++ lpbuildd/target/snapstore.py 2019-06-05 14:11:48 +0000 | |||
247 | @@ -0,0 +1,42 @@ | |||
248 | 1 | # Copyright 2019 Canonical Ltd. This software is licensed under the | ||
249 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
250 | 3 | |||
251 | 4 | from __future__ import print_function | ||
252 | 5 | |||
253 | 6 | __metaclass__ = type | ||
254 | 7 | |||
255 | 8 | import requests | ||
256 | 9 | from six.moves.urllib.parse import ( | ||
257 | 10 | urljoin, | ||
258 | 11 | urlparse, | ||
259 | 12 | urlunparse, | ||
260 | 13 | ) | ||
261 | 14 | |||
262 | 15 | |||
263 | 16 | class SnapStoreOperationMixin: | ||
264 | 17 | """Methods supporting operations that interact with the snap store.""" | ||
265 | 18 | |||
266 | 19 | @classmethod | ||
267 | 20 | def add_arguments(cls, parser): | ||
268 | 21 | super(SnapStoreOperationMixin, cls).add_arguments(parser) | ||
269 | 22 | parser.add_argument( | ||
270 | 23 | "--snap-store-proxy-url", metavar="URL", | ||
271 | 24 | help="snap store proxy URL") | ||
272 | 25 | |||
273 | 26 | def snap_store_set_proxy(self): | ||
274 | 27 | if self.args.snap_store_proxy_url is None: | ||
275 | 28 | return | ||
276 | 29 | # Canonicalise: proxy registration always sends only the scheme and | ||
277 | 30 | # domain. | ||
278 | 31 | parsed_url = urlparse(self.args.snap_store_proxy_url) | ||
279 | 32 | canonical_url = urlunparse( | ||
280 | 33 | [parsed_url.scheme, parsed_url.netloc, "", "", "", ""]) | ||
281 | 34 | assertions_response = requests.get( | ||
282 | 35 | urljoin(canonical_url, "v2/auth/store/assertions")) | ||
283 | 36 | assertions_response.raise_for_status() | ||
284 | 37 | self.backend.run( | ||
285 | 38 | ["snap", "ack", "/dev/stdin"], input_text=assertions_response.text) | ||
286 | 39 | store_id = assertions_response.headers.get("X-Assertion-Store-Id") | ||
287 | 40 | if store_id is not None: | ||
288 | 41 | self.backend.run( | ||
289 | 42 | ["snap", "set", "core", "proxy.store={}".format(store_id)]) | ||
290 | 0 | 43 | ||
291 | === modified file 'lpbuildd/target/tests/test_apt.py' | |||
292 | --- lpbuildd/target/tests/test_apt.py 2019-02-12 10:41:20 +0000 | |||
293 | +++ lpbuildd/target/tests/test_apt.py 2019-06-05 14:11:48 +0000 | |||
294 | @@ -1,4 +1,4 @@ | |||
296 | 1 | # Copyright 2017 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2017-2019 Canonical Ltd. This software is licensed under the |
297 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
298 | 3 | 3 | ||
299 | 4 | __metaclass__ = type | 4 | __metaclass__ = type |
300 | @@ -53,6 +53,27 @@ | |||
301 | 53 | """).encode("UTF-8"), stat.S_IFREG | 0o644), | 53 | """).encode("UTF-8"), stat.S_IFREG | 0o644), |
302 | 54 | override_sources_list.backend.backend_fs["/etc/apt/sources.list"]) | 54 | override_sources_list.backend.backend_fs["/etc/apt/sources.list"]) |
303 | 55 | 55 | ||
304 | 56 | def test_apt_proxy(self): | ||
305 | 57 | args = [ | ||
306 | 58 | "override-sources-list", | ||
307 | 59 | "--backend=fake", "--series=xenial", "--arch=amd64", "1", | ||
308 | 60 | "--apt-proxy-url", "http://apt-proxy.example:3128/", | ||
309 | 61 | "deb http://archive.ubuntu.com/ubuntu xenial main", | ||
310 | 62 | ] | ||
311 | 63 | override_sources_list = parse_args(args=args).operation | ||
312 | 64 | self.assertEqual(0, override_sources_list.run()) | ||
313 | 65 | self.assertEqual( | ||
314 | 66 | (dedent("""\ | ||
315 | 67 | deb http://archive.ubuntu.com/ubuntu xenial main | ||
316 | 68 | """).encode("UTF-8"), stat.S_IFREG | 0o644), | ||
317 | 69 | override_sources_list.backend.backend_fs["/etc/apt/sources.list"]) | ||
318 | 70 | self.assertEqual( | ||
319 | 71 | (dedent("""\ | ||
320 | 72 | Acquire::http::Proxy "http://apt-proxy.example:3128/"; | ||
321 | 73 | """).encode("UTF-8"), stat.S_IFREG | 0o644), | ||
322 | 74 | override_sources_list.backend.backend_fs[ | ||
323 | 75 | "/etc/apt/apt.conf.d/99proxy"]) | ||
324 | 76 | |||
325 | 56 | 77 | ||
326 | 57 | class TestAddTrustedKeys(TestCase): | 78 | class TestAddTrustedKeys(TestCase): |
327 | 58 | 79 | ||
328 | 59 | 80 | ||
329 | === modified file 'lpbuildd/target/tests/test_build_livefs.py' | |||
330 | --- lpbuildd/target/tests/test_build_livefs.py 2019-02-12 10:41:20 +0000 | |||
331 | +++ lpbuildd/target/tests/test_build_livefs.py 2019-06-05 14:11:48 +0000 | |||
332 | @@ -1,11 +1,13 @@ | |||
334 | 1 | # Copyright 2017 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2017-2019 Canonical Ltd. This software is licensed under the |
335 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
336 | 3 | 3 | ||
337 | 4 | __metaclass__ = type | 4 | __metaclass__ = type |
338 | 5 | 5 | ||
339 | 6 | import subprocess | 6 | import subprocess |
340 | 7 | from textwrap import dedent | ||
341 | 7 | 8 | ||
342 | 8 | from fixtures import FakeLogger | 9 | from fixtures import FakeLogger |
343 | 10 | import responses | ||
344 | 9 | from testtools import TestCase | 11 | from testtools import TestCase |
345 | 10 | from testtools.matchers import ( | 12 | from testtools.matchers import ( |
346 | 11 | AnyMatch, | 13 | AnyMatch, |
347 | @@ -26,12 +28,17 @@ | |||
348 | 26 | 28 | ||
349 | 27 | class RanCommand(MatchesListwise): | 29 | class RanCommand(MatchesListwise): |
350 | 28 | 30 | ||
352 | 29 | def __init__(self, args, echo=None, cwd=None, **env): | 31 | def __init__(self, args, echo=None, cwd=None, input_text=None, |
353 | 32 | get_output=None, **env): | ||
354 | 30 | kwargs_matcher = {} | 33 | kwargs_matcher = {} |
355 | 31 | if echo is not None: | 34 | if echo is not None: |
356 | 32 | kwargs_matcher["echo"] = Is(echo) | 35 | kwargs_matcher["echo"] = Is(echo) |
357 | 33 | if cwd: | 36 | if cwd: |
358 | 34 | kwargs_matcher["cwd"] = Equals(cwd) | 37 | kwargs_matcher["cwd"] = Equals(cwd) |
359 | 38 | if input_text: | ||
360 | 39 | kwargs_matcher["input_text"] = Equals(input_text) | ||
361 | 40 | if get_output is not None: | ||
362 | 41 | kwargs_matcher["get_output"] = Is(get_output) | ||
363 | 35 | if env: | 42 | if env: |
364 | 36 | kwargs_matcher["env"] = MatchesDict( | 43 | kwargs_matcher["env"] = MatchesDict( |
365 | 37 | {key: Equals(value) for key, value in env.items()}) | 44 | {key: Equals(value) for key, value in env.items()}) |
366 | @@ -113,6 +120,36 @@ | |||
367 | 113 | "--install-recommends", "install", "ubuntu-defaults-builder"), | 120 | "--install-recommends", "install", "ubuntu-defaults-builder"), |
368 | 114 | ])) | 121 | ])) |
369 | 115 | 122 | ||
370 | 123 | @responses.activate | ||
371 | 124 | def test_install_snap_store_proxy(self): | ||
372 | 125 | store_assertion = dedent("""\ | ||
373 | 126 | type: store | ||
374 | 127 | store: store-id | ||
375 | 128 | url: http://snap-store-proxy.example | ||
376 | 129 | |||
377 | 130 | body | ||
378 | 131 | """) | ||
379 | 132 | |||
380 | 133 | def respond(request): | ||
381 | 134 | return 200, {"X-Assertion-Store-Id": "store-id"}, store_assertion | ||
382 | 135 | |||
383 | 136 | responses.add_callback( | ||
384 | 137 | "GET", "http://snap-store-proxy.example/v2/auth/store/assertions", | ||
385 | 138 | callback=respond) | ||
386 | 139 | args = [ | ||
387 | 140 | "buildlivefs", | ||
388 | 141 | "--backend=fake", "--series=xenial", "--arch=amd64", "1", | ||
389 | 142 | "--snap-store-proxy-url", "http://snap-store-proxy.example/", | ||
390 | 143 | ] | ||
391 | 144 | build_livefs = parse_args(args=args).operation | ||
392 | 145 | build_livefs.install() | ||
393 | 146 | self.assertThat(build_livefs.backend.run.calls, MatchesListwise([ | ||
394 | 147 | RanAptGet("install", "livecd-rootfs"), | ||
395 | 148 | RanCommand( | ||
396 | 149 | ["snap", "ack", "/dev/stdin"], input_text=store_assertion), | ||
397 | 150 | RanCommand(["snap", "set", "core", "proxy.store=store-id"]), | ||
398 | 151 | ])) | ||
399 | 152 | |||
400 | 116 | def test_build(self): | 153 | def test_build(self): |
401 | 117 | args = [ | 154 | args = [ |
402 | 118 | "buildlivefs", | 155 | "buildlivefs", |
403 | 119 | 156 | ||
404 | === modified file 'lpbuildd/target/tests/test_build_snap.py' | |||
405 | --- lpbuildd/target/tests/test_build_snap.py 2019-05-08 14:52:28 +0000 | |||
406 | +++ lpbuildd/target/tests/test_build_snap.py 2019-06-05 14:11:48 +0000 | |||
407 | @@ -1,4 +1,4 @@ | |||
409 | 1 | # Copyright 2017 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2017-2019 Canonical Ltd. This software is licensed under the |
410 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
411 | 3 | 3 | ||
412 | 4 | __metaclass__ = type | 4 | __metaclass__ = type |
413 | @@ -7,11 +7,13 @@ | |||
414 | 7 | import os.path | 7 | import os.path |
415 | 8 | import stat | 8 | import stat |
416 | 9 | import subprocess | 9 | import subprocess |
417 | 10 | from textwrap import dedent | ||
418 | 10 | 11 | ||
419 | 11 | from fixtures import ( | 12 | from fixtures import ( |
420 | 12 | FakeLogger, | 13 | FakeLogger, |
421 | 13 | TempDir, | 14 | TempDir, |
422 | 14 | ) | 15 | ) |
423 | 16 | import responses | ||
424 | 15 | from systemfixtures import FakeFilesystem | 17 | from systemfixtures import FakeFilesystem |
425 | 16 | from testtools import TestCase | 18 | from testtools import TestCase |
426 | 17 | from testtools.matchers import ( | 19 | from testtools.matchers import ( |
427 | @@ -33,14 +35,17 @@ | |||
428 | 33 | 35 | ||
429 | 34 | class RanCommand(MatchesListwise): | 36 | class RanCommand(MatchesListwise): |
430 | 35 | 37 | ||
432 | 36 | def __init__(self, args, get_output=None, echo=None, cwd=None, **env): | 38 | def __init__(self, args, echo=None, cwd=None, input_text=None, |
433 | 39 | get_output=None, **env): | ||
434 | 37 | kwargs_matcher = {} | 40 | kwargs_matcher = {} |
435 | 38 | if get_output is not None: | ||
436 | 39 | kwargs_matcher["get_output"] = Is(get_output) | ||
437 | 40 | if echo is not None: | 41 | if echo is not None: |
438 | 41 | kwargs_matcher["echo"] = Is(echo) | 42 | kwargs_matcher["echo"] = Is(echo) |
439 | 42 | if cwd: | 43 | if cwd: |
440 | 43 | kwargs_matcher["cwd"] = Equals(cwd) | 44 | kwargs_matcher["cwd"] = Equals(cwd) |
441 | 45 | if input_text: | ||
442 | 46 | kwargs_matcher["input_text"] = Equals(input_text) | ||
443 | 47 | if get_output is not None: | ||
444 | 48 | kwargs_matcher["get_output"] = Is(get_output) | ||
445 | 44 | if env: | 49 | if env: |
446 | 45 | kwargs_matcher["env"] = MatchesDict( | 50 | kwargs_matcher["env"] = MatchesDict( |
447 | 46 | {key: Equals(value) for key, value in env.items()}) | 51 | {key: Equals(value) for key, value in env.items()}) |
448 | @@ -132,6 +137,38 @@ | |||
449 | 132 | RanAptGet("install", "git", "snapcraft"), | 137 | RanAptGet("install", "git", "snapcraft"), |
450 | 133 | ])) | 138 | ])) |
451 | 134 | 139 | ||
452 | 140 | @responses.activate | ||
453 | 141 | def test_install_snap_store_proxy(self): | ||
454 | 142 | store_assertion = dedent("""\ | ||
455 | 143 | type: store | ||
456 | 144 | store: store-id | ||
457 | 145 | url: http://snap-store-proxy.example | ||
458 | 146 | |||
459 | 147 | body | ||
460 | 148 | """) | ||
461 | 149 | |||
462 | 150 | def respond(request): | ||
463 | 151 | return 200, {"X-Assertion-Store-Id": "store-id"}, store_assertion | ||
464 | 152 | |||
465 | 153 | responses.add_callback( | ||
466 | 154 | "GET", "http://snap-store-proxy.example/v2/auth/store/assertions", | ||
467 | 155 | callback=respond) | ||
468 | 156 | args = [ | ||
469 | 157 | "buildsnap", | ||
470 | 158 | "--backend=fake", "--series=xenial", "--arch=amd64", "1", | ||
471 | 159 | "--git-repository", "lp:foo", | ||
472 | 160 | "--snap-store-proxy-url", "http://snap-store-proxy.example/", | ||
473 | 161 | "test-snap", | ||
474 | 162 | ] | ||
475 | 163 | build_snap = parse_args(args=args).operation | ||
476 | 164 | build_snap.install() | ||
477 | 165 | self.assertThat(build_snap.backend.run.calls, MatchesListwise([ | ||
478 | 166 | RanAptGet("install", "git", "snapcraft"), | ||
479 | 167 | RanCommand( | ||
480 | 168 | ["snap", "ack", "/dev/stdin"], input_text=store_assertion), | ||
481 | 169 | RanCommand(["snap", "set", "core", "proxy.store=store-id"]), | ||
482 | 170 | ])) | ||
483 | 171 | |||
484 | 135 | def test_install_proxy(self): | 172 | def test_install_proxy(self): |
485 | 136 | args = [ | 173 | args = [ |
486 | 137 | "buildsnap", | 174 | "buildsnap", |
487 | 138 | 175 | ||
488 | === modified file 'lpbuildd/tests/fakebuilder.py' | |||
489 | --- lpbuildd/tests/fakebuilder.py 2019-02-12 10:41:20 +0000 | |||
490 | +++ lpbuildd/tests/fakebuilder.py 2019-06-05 14:11:48 +0000 | |||
491 | @@ -1,4 +1,4 @@ | |||
493 | 1 | # Copyright 2013 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2013-2019 Canonical Ltd. This software is licensed under the |
494 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
495 | 3 | 3 | ||
496 | 4 | __metaclass__ = type | 4 | __metaclass__ = type |
497 | @@ -9,12 +9,18 @@ | |||
498 | 9 | 'UncontainedBackend', | 9 | 'UncontainedBackend', |
499 | 10 | ] | 10 | ] |
500 | 11 | 11 | ||
501 | 12 | from collections import defaultdict | ||
502 | 12 | import hashlib | 13 | import hashlib |
503 | 13 | import os | 14 | import os |
504 | 14 | import shutil | 15 | import shutil |
505 | 15 | import stat | 16 | import stat |
506 | 16 | import subprocess | 17 | import subprocess |
507 | 17 | 18 | ||
508 | 19 | from six.moves.configparser import ( | ||
509 | 20 | NoOptionError, | ||
510 | 21 | NoSectionError, | ||
511 | 22 | ) | ||
512 | 23 | |||
513 | 18 | from lpbuildd.target.backend import Backend | 24 | from lpbuildd.target.backend import Backend |
514 | 19 | from lpbuildd.util import ( | 25 | from lpbuildd.util import ( |
515 | 20 | set_personality, | 26 | set_personality, |
516 | @@ -78,8 +84,22 @@ | |||
517 | 78 | 84 | ||
518 | 79 | 85 | ||
519 | 80 | class FakeConfig: | 86 | class FakeConfig: |
520 | 87 | def __init__(self): | ||
521 | 88 | self._overrides = defaultdict(dict) | ||
522 | 89 | |||
523 | 81 | def get(self, section, key): | 90 | def get(self, section, key): |
525 | 82 | return key | 91 | if key in self._overrides[section]: |
526 | 92 | return self._overrides[section][key] | ||
527 | 93 | elif section == "proxy": | ||
528 | 94 | if not self._overrides[section]: | ||
529 | 95 | raise NoSectionError(section) | ||
530 | 96 | else: | ||
531 | 97 | raise NoOptionError(section, key) | ||
532 | 98 | else: | ||
533 | 99 | return key | ||
534 | 100 | |||
535 | 101 | def set(self, section, key, value): | ||
536 | 102 | self._overrides[section][key] = value | ||
537 | 83 | 103 | ||
538 | 84 | 104 | ||
539 | 85 | class FakeBuilder: | 105 | class FakeBuilder: |
540 | 86 | 106 | ||
541 | === modified file 'lpbuildd/tests/test_debian.py' | |||
542 | --- lpbuildd/tests/test_debian.py 2019-02-12 10:41:20 +0000 | |||
543 | +++ lpbuildd/tests/test_debian.py 2019-06-05 14:11:48 +0000 | |||
544 | @@ -1,4 +1,4 @@ | |||
546 | 1 | # Copyright 2017 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2017-2019 Canonical Ltd. This software is licensed under the |
547 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
548 | 3 | 3 | ||
549 | 4 | __metaclass__ = type | 4 | __metaclass__ = type |
550 | @@ -404,6 +404,36 @@ | |||
551 | 404 | self.assertTrue(self.builder.wasCalled('buildOK')) | 404 | self.assertTrue(self.builder.wasCalled('buildOK')) |
552 | 405 | self.assertTrue(self.builder.wasCalled('buildComplete')) | 405 | self.assertTrue(self.builder.wasCalled('buildComplete')) |
553 | 406 | 406 | ||
554 | 407 | def test_iterate_apt_proxy(self): | ||
555 | 408 | # The build manager can be configured to use an APT proxy. | ||
556 | 409 | self.builder._config.set( | ||
557 | 410 | 'proxy', 'apt', 'http://apt-proxy.example:3128/') | ||
558 | 411 | extra_args = { | ||
559 | 412 | 'arch_tag': 'amd64', | ||
560 | 413 | 'archives': [ | ||
561 | 414 | 'deb http://ppa.launchpad.dev/owner/name/ubuntu xenial main', | ||
562 | 415 | ], | ||
563 | 416 | 'series': 'xenial', | ||
564 | 417 | } | ||
565 | 418 | self.startBuild(extra_args) | ||
566 | 419 | |||
567 | 420 | self.buildmanager.iterate(0) | ||
568 | 421 | self.assertEqual(DebianBuildState.UNPACK, self.getState()) | ||
569 | 422 | self.buildmanager.iterate(0) | ||
570 | 423 | self.assertEqual(DebianBuildState.MOUNT, self.getState()) | ||
571 | 424 | self.buildmanager.iterate(0) | ||
572 | 425 | self.assertEqual(DebianBuildState.SOURCES, self.getState()) | ||
573 | 426 | self.assertEqual( | ||
574 | 427 | (['sharepath/bin/in-target', 'in-target', 'override-sources-list', | ||
575 | 428 | '--backend=chroot', '--series=xenial', '--arch=amd64', | ||
576 | 429 | self.buildid, | ||
577 | 430 | '--apt-proxy-url', 'http://apt-proxy.example:3128/', | ||
578 | 431 | 'deb http://ppa.launchpad.dev/owner/name/ubuntu xenial main'], | ||
579 | 432 | None), | ||
580 | 433 | self.buildmanager.commands[-1]) | ||
581 | 434 | self.assertEqual( | ||
582 | 435 | self.buildmanager.iterate, self.buildmanager.iterators[-1]) | ||
583 | 436 | |||
584 | 407 | def test_iterate_lxd(self): | 437 | def test_iterate_lxd(self): |
585 | 408 | # The build manager passes the image_type argument through to | 438 | # The build manager passes the image_type argument through to |
586 | 409 | # unpack-chroot. | 439 | # unpack-chroot. |
587 | 410 | 440 | ||
588 | === modified file 'lpbuildd/tests/test_livefs.py' | |||
589 | --- lpbuildd/tests/test_livefs.py 2019-02-12 10:41:20 +0000 | |||
590 | +++ lpbuildd/tests/test_livefs.py 2019-06-05 14:11:48 +0000 | |||
591 | @@ -1,4 +1,4 @@ | |||
593 | 1 | # Copyright 2013-2018 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2013-2019 Canonical Ltd. This software is licensed under the |
594 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
595 | 3 | 3 | ||
596 | 4 | __metaclass__ = type | 4 | __metaclass__ = type |
597 | @@ -58,7 +58,7 @@ | |||
598 | 58 | return self.buildmanager._state | 58 | return self.buildmanager._state |
599 | 59 | 59 | ||
600 | 60 | @defer.inlineCallbacks | 60 | @defer.inlineCallbacks |
602 | 61 | def startBuild(self): | 61 | def startBuild(self, options=None): |
603 | 62 | # The build manager's iterate() kicks off the consecutive states | 62 | # The build manager's iterate() kicks off the consecutive states |
604 | 63 | # after INIT. | 63 | # after INIT. |
605 | 64 | extra_args = { | 64 | extra_args = { |
606 | @@ -85,6 +85,8 @@ | |||
607 | 85 | "--backend=lxd", "--series=saucy", "--arch=i386", self.buildid, | 85 | "--backend=lxd", "--series=saucy", "--arch=i386", self.buildid, |
608 | 86 | "--project", "ubuntu", | 86 | "--project", "ubuntu", |
609 | 87 | ] | 87 | ] |
610 | 88 | if options is not None: | ||
611 | 89 | expected_command.extend(options) | ||
612 | 88 | self.assertEqual(expected_command, self.buildmanager.commands[-1]) | 90 | self.assertEqual(expected_command, self.buildmanager.commands[-1]) |
613 | 89 | self.assertEqual( | 91 | self.assertEqual( |
614 | 90 | self.buildmanager.iterate, self.buildmanager.iterators[-1]) | 92 | self.buildmanager.iterate, self.buildmanager.iterators[-1]) |
615 | @@ -131,6 +133,15 @@ | |||
616 | 131 | self.assertFalse(self.builder.wasCalled("buildFail")) | 133 | self.assertFalse(self.builder.wasCalled("buildFail")) |
617 | 132 | 134 | ||
618 | 133 | @defer.inlineCallbacks | 135 | @defer.inlineCallbacks |
619 | 136 | def test_iterate_snap_store_proxy(self): | ||
620 | 137 | # The build manager can be told to use a snap store proxy. | ||
621 | 138 | self.builder._config.set( | ||
622 | 139 | "proxy", "snapstore", "http://snap-store-proxy.example/") | ||
623 | 140 | expected_options = [ | ||
624 | 141 | "--snap-store-proxy-url", "http://snap-store-proxy.example/"] | ||
625 | 142 | yield self.startBuild(options=expected_options) | ||
626 | 143 | |||
627 | 144 | @defer.inlineCallbacks | ||
628 | 134 | def test_omits_symlinks(self): | 145 | def test_omits_symlinks(self): |
629 | 135 | # Symlinks in the build output are not included in gathered results. | 146 | # Symlinks in the build output are not included in gathered results. |
630 | 136 | yield self.startBuild() | 147 | yield self.startBuild() |
631 | 137 | 148 | ||
632 | === modified file 'lpbuildd/tests/test_snap.py' | |||
633 | --- lpbuildd/tests/test_snap.py 2019-05-22 17:59:14 +0000 | |||
634 | +++ lpbuildd/tests/test_snap.py 2019-06-05 14:11:48 +0000 | |||
635 | @@ -1,4 +1,4 @@ | |||
637 | 1 | # Copyright 2015-2018 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2015-2019 Canonical Ltd. This software is licensed under the |
638 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
639 | 3 | 3 | ||
640 | 4 | __metaclass__ = type | 4 | __metaclass__ = type |
641 | @@ -377,6 +377,15 @@ | |||
642 | 377 | self.buildmanager.iterate, self.buildmanager.iterators[-1]) | 377 | self.buildmanager.iterate, self.buildmanager.iterators[-1]) |
643 | 378 | self.assertFalse(self.builder.wasCalled("buildFail")) | 378 | self.assertFalse(self.builder.wasCalled("buildFail")) |
644 | 379 | 379 | ||
645 | 380 | @defer.inlineCallbacks | ||
646 | 381 | def test_iterate_snap_store_proxy(self): | ||
647 | 382 | # The build manager can be told to use a snap store proxy. | ||
648 | 383 | self.builder._config.set( | ||
649 | 384 | "proxy", "snapstore", "http://snap-store-proxy.example/") | ||
650 | 385 | expected_options = [ | ||
651 | 386 | "--snap-store-proxy-url", "http://snap-store-proxy.example/"] | ||
652 | 387 | yield self.startBuild(options=expected_options) | ||
653 | 388 | |||
654 | 380 | def getListenerURL(self, listener): | 389 | def getListenerURL(self, listener): |
655 | 381 | port = listener.getHost().port | 390 | port = listener.getHost().port |
656 | 382 | return b"http://localhost:%d/" % port | 391 | return b"http://localhost:%d/" % port |
657 | 383 | 392 | ||
658 | === modified file 'setup.py' | |||
659 | --- setup.py 2018-10-25 09:04:12 +0000 | |||
660 | +++ setup.py 2019-06-05 14:11:48 +0000 | |||
661 | @@ -1,6 +1,6 @@ | |||
662 | 1 | #!/usr/bin/env python | 1 | #!/usr/bin/env python |
663 | 2 | 2 | ||
665 | 3 | # Copyright 2015 Canonical Ltd. All rights reserved. | 3 | # Copyright 2015-2019 Canonical Ltd. All rights reserved. |
666 | 4 | # | 4 | # |
667 | 5 | # This file is part of launchpad-buildd. | 5 | # This file is part of launchpad-buildd. |
668 | 6 | # | 6 | # |
669 | @@ -59,6 +59,8 @@ | |||
670 | 59 | # causes problems for Launchpad's build system. | 59 | # causes problems for Launchpad's build system. |
671 | 60 | #'python-apt', | 60 | #'python-apt', |
672 | 61 | 'python-debian>=0.1.23', | 61 | 'python-debian>=0.1.23', |
673 | 62 | 'requests', | ||
674 | 63 | 'six', | ||
675 | 62 | 'Twisted', | 64 | 'Twisted', |
676 | 63 | 'zope.interface', | 65 | 'zope.interface', |
677 | 64 | ], | 66 | ], |
678 | @@ -69,6 +71,7 @@ | |||
679 | 69 | tests_require=[ | 71 | tests_require=[ |
680 | 70 | 'fixtures', | 72 | 'fixtures', |
681 | 71 | 'mock', | 73 | 'mock', |
682 | 74 | 'responses', | ||
683 | 72 | 'systemfixtures', | 75 | 'systemfixtures', |
684 | 73 | 'testtools', | 76 | 'testtools', |
685 | 74 | 'txfixtures', | 77 | 'txfixtures', |