Merge lp:~cjwatson/launchpad-buildd/proxy-configs into lp:launchpad-buildd

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
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
=== modified file 'debian/changelog'
--- debian/changelog 2019-05-23 16:23:54 +0000
+++ debian/changelog 2019-06-05 14:11:48 +0000
@@ -1,3 +1,10 @@
1launchpad-buildd (175) UNRELEASED; urgency=medium
2
3 * Allow configuring APT or snap store proxies via a new [proxy]
4 configuration file section.
5
6 -- Colin Watson <cjwatson@ubuntu.com> Wed, 05 Jun 2019 15:06:54 +0100
7
1launchpad-buildd (174) xenial; urgency=medium8launchpad-buildd (174) xenial; urgency=medium
29
3 * Fix a missing piece from the changes in launchpad-buildd 168 that were10 * Fix a missing piece from the changes in launchpad-buildd 168 that were
411
=== modified file 'debian/control'
--- debian/control 2018-06-07 16:23:18 +0000
+++ debian/control 2019-06-05 14:11:48 +0000
@@ -17,7 +17,10 @@
17 python-mock,17 python-mock,
18 python-netaddr,18 python-netaddr,
19 python-pylxd,19 python-pylxd,
20 python-requests,
21 python-responses,
20 python-setuptools,22 python-setuptools,
23 python-six,
21 python-systemfixtures,24 python-systemfixtures,
22 python-testtools,25 python-testtools,
23 python-twisted,26 python-twisted,
2427
=== modified file 'lpbuildd/debian.py'
--- lpbuildd/debian.py 2019-02-12 10:35:12 +0000
+++ lpbuildd/debian.py 2019-06-05 14:11:48 +0000
@@ -1,4 +1,4 @@
1# Copyright 2009-2018 Canonical Ltd. This software is licensed under the1# Copyright 2009-2019 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4# Authors: Daniel Silverstone <daniel.silverstone@canonical.com>4# Authors: Daniel Silverstone <daniel.silverstone@canonical.com>
@@ -11,6 +11,10 @@
11import re11import re
12import signal12import signal
1313
14from six.moves.configparser import (
15 NoOptionError,
16 NoSectionError,
17 )
14from twisted.internet import (18from twisted.internet import (
15 defer,19 defer,
16 threads,20 threads,
@@ -59,7 +63,14 @@
5963
60 Mainly used for PPA builds.64 Mainly used for PPA builds.
61 """65 """
62 self.runTargetSubProcess("override-sources-list", *self.sources_list)66 args = []
67 try:
68 apt_proxy_url = self._builder._config.get("proxy", "apt")
69 args.extend(["--apt-proxy-url", apt_proxy_url])
70 except (NoSectionError, NoOptionError):
71 pass
72 args.extend(self.sources_list)
73 self.runTargetSubProcess("override-sources-list", *args)
6374
64 def doTrustedKeys(self):75 def doTrustedKeys(self):
65 """Add trusted keys."""76 """Add trusted keys."""
6677
=== modified file 'lpbuildd/livefs.py'
--- lpbuildd/livefs.py 2019-02-12 10:35:12 +0000
+++ lpbuildd/livefs.py 2019-06-05 14:11:48 +0000
@@ -1,10 +1,15 @@
1# Copyright 2013-2018 Canonical Ltd. This software is licensed under the1# Copyright 2013-2019 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4__metaclass__ = type4__metaclass__ = type
55
6import os6import os
77
8from six.moves.configparser import (
9 NoOptionError,
10 NoSectionError,
11 )
12
8from lpbuildd.debian import (13from lpbuildd.debian import (
9 DebianBuildManager,14 DebianBuildManager,
10 DebianBuildState,15 DebianBuildState,
@@ -71,6 +76,12 @@
71 args.extend(["--repo-snapshot-stamp", self.repo_snapshot_stamp])76 args.extend(["--repo-snapshot-stamp", self.repo_snapshot_stamp])
72 if self.cohort_key:77 if self.cohort_key:
73 args.extend(["--cohort-key", self.cohort_key])78 args.extend(["--cohort-key", self.cohort_key])
79 try:
80 snap_store_proxy_url = self._builder._config.get(
81 "proxy", "snapstore")
82 args.extend(["--snap-store-proxy-url", snap_store_proxy_url])
83 except (NoSectionError, NoOptionError):
84 pass
74 if self.debug:85 if self.debug:
75 args.append("--debug")86 args.append("--debug")
76 self.runTargetSubProcess("buildlivefs", *args)87 self.runTargetSubProcess("buildlivefs", *args)
7788
=== modified file 'lpbuildd/snap.py'
--- lpbuildd/snap.py 2019-05-22 17:59:14 +0000
+++ lpbuildd/snap.py 2019-06-05 14:11:48 +0000
@@ -1,4 +1,4 @@
1# Copyright 2015-2018 Canonical Ltd. This software is licensed under the1# Copyright 2015-2019 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4from __future__ import print_function4from __future__ import print_function
@@ -29,6 +29,10 @@
29 )29 )
30 from urlparse import urlparse30 from urlparse import urlparse
3131
32from six.moves.configparser import (
33 NoOptionError,
34 NoSectionError,
35 )
32from twisted.application import strports36from twisted.application import strports
33from twisted.internet import reactor37from twisted.internet import reactor
34from twisted.internet.interfaces import IHalfCloseableProtocol38from twisted.internet.interfaces import IHalfCloseableProtocol
@@ -351,6 +355,12 @@
351 args.append("--build-source-tarball")355 args.append("--build-source-tarball")
352 if self.private:356 if self.private:
353 args.append("--private")357 args.append("--private")
358 try:
359 snap_store_proxy_url = self._builder._config.get(
360 "proxy", "snapstore")
361 args.extend(["--snap-store-proxy-url", snap_store_proxy_url])
362 except (NoSectionError, NoOptionError):
363 pass
354 args.append(self.name)364 args.append(self.name)
355 self.runTargetSubProcess("buildsnap", *args)365 self.runTargetSubProcess("buildsnap", *args)
356366
357367
=== modified file 'lpbuildd/target/apt.py'
--- lpbuildd/target/apt.py 2017-08-22 15:55:44 +0000
+++ lpbuildd/target/apt.py 2019-06-05 14:11:48 +0000
@@ -1,4 +1,4 @@
1# Copyright 2009-2017 Canonical Ltd. This software is licensed under the1# Copyright 2009-2019 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4from __future__ import print_function4from __future__ import print_function
@@ -26,6 +26,8 @@
26 def add_arguments(cls, parser):26 def add_arguments(cls, parser):
27 super(OverrideSourcesList, cls).add_arguments(parser)27 super(OverrideSourcesList, cls).add_arguments(parser)
28 parser.add_argument(28 parser.add_argument(
29 "--apt-proxy-url", metavar="URL", help="APT proxy URL")
30 parser.add_argument(
29 "archives", metavar="ARCHIVE", nargs="+",31 "archives", metavar="ARCHIVE", nargs="+",
30 help="sources.list lines")32 help="sources.list lines")
3133
@@ -37,6 +39,16 @@
37 sources_list.flush()39 sources_list.flush()
38 os.fchmod(sources_list.fileno(), 0o644)40 os.fchmod(sources_list.fileno(), 0o644)
39 self.backend.copy_in(sources_list.name, "/etc/apt/sources.list")41 self.backend.copy_in(sources_list.name, "/etc/apt/sources.list")
42 if self.args.apt_proxy_url is not None:
43 with tempfile.NamedTemporaryFile() as apt_proxy_conf:
44 print(
45 'Acquire::http::Proxy "{}";'.format(
46 self.args.apt_proxy_url),
47 file=apt_proxy_conf)
48 apt_proxy_conf.flush()
49 os.fchmod(apt_proxy_conf.fileno(), 0o644)
50 self.backend.copy_in(
51 apt_proxy_conf.name, "/etc/apt/apt.conf.d/99proxy")
40 return 052 return 0
4153
4254
4355
=== modified file 'lpbuildd/target/build_livefs.py'
--- lpbuildd/target/build_livefs.py 2019-01-28 13:10:24 +0000
+++ lpbuildd/target/build_livefs.py 2019-06-05 14:11:48 +0000
@@ -1,4 +1,4 @@
1# Copyright 2013-2017 Canonical Ltd. This software is licensed under the1# Copyright 2013-2019 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4from __future__ import print_function4from __future__ import print_function
@@ -10,6 +10,7 @@
10import os10import os
1111
12from lpbuildd.target.operation import Operation12from lpbuildd.target.operation import Operation
13from lpbuildd.target.snapstore import SnapStoreOperationMixin
1314
1415
15RETCODE_FAILURE_INSTALL = 20016RETCODE_FAILURE_INSTALL = 200
@@ -29,7 +30,7 @@
29 return os.path.join(os.environ["HOME"], "build-" + build_id, *extra)30 return os.path.join(os.environ["HOME"], "build-" + build_id, *extra)
3031
3132
32class BuildLiveFS(Operation):33class BuildLiveFS(SnapStoreOperationMixin, Operation):
3334
34 description = "Build a live file system."35 description = "Build a live file system."
3536
@@ -94,6 +95,8 @@
94 if self.backend.is_package_available(dep):95 if self.backend.is_package_available(dep):
95 deps.append(dep)96 deps.append(dep)
96 self.backend.run(["apt-get", "-y", "install"] + deps)97 self.backend.run(["apt-get", "-y", "install"] + deps)
98 if self.args.backend in ("lxd", "fake"):
99 self.snap_store_set_proxy()
97 if self.args.arch == "i386":100 if self.args.arch == "i386":
98 self.backend.run([101 self.backend.run([
99 "apt-get", "-y", "--no-install-recommends", "install",102 "apt-get", "-y", "--no-install-recommends", "install",
100103
=== modified file 'lpbuildd/target/build_snap.py'
--- lpbuildd/target/build_snap.py 2019-05-08 14:52:28 +0000
+++ lpbuildd/target/build_snap.py 2019-06-05 14:11:48 +0000
@@ -1,4 +1,4 @@
1# Copyright 2015-2017 Canonical Ltd. This software is licensed under the1# Copyright 2015-2019 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4from __future__ import print_function4from __future__ import print_function
@@ -19,6 +19,7 @@
19 from urlparse import urlparse19 from urlparse import urlparse
2020
21from lpbuildd.target.operation import Operation21from lpbuildd.target.operation import Operation
22from lpbuildd.target.snapstore import SnapStoreOperationMixin
22from lpbuildd.target.vcs import VCSOperationMixin23from lpbuildd.target.vcs import VCSOperationMixin
2324
2425
@@ -47,7 +48,7 @@
47 getattr(namespace, self.dest)[snap] = channel48 getattr(namespace, self.dest)[snap] = channel
4849
4950
50class BuildSnap(VCSOperationMixin, Operation):51class BuildSnap(VCSOperationMixin, SnapStoreOperationMixin, Operation):
5152
52 description = "Build a snap."53 description = "Build a snap."
5354
@@ -154,6 +155,8 @@
154 else:155 else:
155 deps.append("snapcraft")156 deps.append("snapcraft")
156 self.backend.run(["apt-get", "-y", "install"] + deps)157 self.backend.run(["apt-get", "-y", "install"] + deps)
158 if self.args.backend in ("lxd", "fake"):
159 self.snap_store_set_proxy()
157 for snap_name in self.core_snap_names:160 for snap_name in self.core_snap_names:
158 if snap_name in self.args.channels:161 if snap_name in self.args.channels:
159 self.backend.run(162 self.backend.run(
160163
=== added file 'lpbuildd/target/snapstore.py'
--- lpbuildd/target/snapstore.py 1970-01-01 00:00:00 +0000
+++ lpbuildd/target/snapstore.py 2019-06-05 14:11:48 +0000
@@ -0,0 +1,42 @@
1# Copyright 2019 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4from __future__ import print_function
5
6__metaclass__ = type
7
8import requests
9from six.moves.urllib.parse import (
10 urljoin,
11 urlparse,
12 urlunparse,
13 )
14
15
16class SnapStoreOperationMixin:
17 """Methods supporting operations that interact with the snap store."""
18
19 @classmethod
20 def add_arguments(cls, parser):
21 super(SnapStoreOperationMixin, cls).add_arguments(parser)
22 parser.add_argument(
23 "--snap-store-proxy-url", metavar="URL",
24 help="snap store proxy URL")
25
26 def snap_store_set_proxy(self):
27 if self.args.snap_store_proxy_url is None:
28 return
29 # Canonicalise: proxy registration always sends only the scheme and
30 # domain.
31 parsed_url = urlparse(self.args.snap_store_proxy_url)
32 canonical_url = urlunparse(
33 [parsed_url.scheme, parsed_url.netloc, "", "", "", ""])
34 assertions_response = requests.get(
35 urljoin(canonical_url, "v2/auth/store/assertions"))
36 assertions_response.raise_for_status()
37 self.backend.run(
38 ["snap", "ack", "/dev/stdin"], input_text=assertions_response.text)
39 store_id = assertions_response.headers.get("X-Assertion-Store-Id")
40 if store_id is not None:
41 self.backend.run(
42 ["snap", "set", "core", "proxy.store={}".format(store_id)])
043
=== modified file 'lpbuildd/target/tests/test_apt.py'
--- lpbuildd/target/tests/test_apt.py 2019-02-12 10:41:20 +0000
+++ lpbuildd/target/tests/test_apt.py 2019-06-05 14:11:48 +0000
@@ -1,4 +1,4 @@
1# Copyright 2017 Canonical Ltd. This software is licensed under the1# Copyright 2017-2019 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4__metaclass__ = type4__metaclass__ = type
@@ -53,6 +53,27 @@
53 """).encode("UTF-8"), stat.S_IFREG | 0o644),53 """).encode("UTF-8"), stat.S_IFREG | 0o644),
54 override_sources_list.backend.backend_fs["/etc/apt/sources.list"])54 override_sources_list.backend.backend_fs["/etc/apt/sources.list"])
5555
56 def test_apt_proxy(self):
57 args = [
58 "override-sources-list",
59 "--backend=fake", "--series=xenial", "--arch=amd64", "1",
60 "--apt-proxy-url", "http://apt-proxy.example:3128/",
61 "deb http://archive.ubuntu.com/ubuntu xenial main",
62 ]
63 override_sources_list = parse_args(args=args).operation
64 self.assertEqual(0, override_sources_list.run())
65 self.assertEqual(
66 (dedent("""\
67 deb http://archive.ubuntu.com/ubuntu xenial main
68 """).encode("UTF-8"), stat.S_IFREG | 0o644),
69 override_sources_list.backend.backend_fs["/etc/apt/sources.list"])
70 self.assertEqual(
71 (dedent("""\
72 Acquire::http::Proxy "http://apt-proxy.example:3128/";
73 """).encode("UTF-8"), stat.S_IFREG | 0o644),
74 override_sources_list.backend.backend_fs[
75 "/etc/apt/apt.conf.d/99proxy"])
76
5677
57class TestAddTrustedKeys(TestCase):78class TestAddTrustedKeys(TestCase):
5879
5980
=== modified file 'lpbuildd/target/tests/test_build_livefs.py'
--- lpbuildd/target/tests/test_build_livefs.py 2019-02-12 10:41:20 +0000
+++ lpbuildd/target/tests/test_build_livefs.py 2019-06-05 14:11:48 +0000
@@ -1,11 +1,13 @@
1# Copyright 2017 Canonical Ltd. This software is licensed under the1# Copyright 2017-2019 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4__metaclass__ = type4__metaclass__ = type
55
6import subprocess6import subprocess
7from textwrap import dedent
78
8from fixtures import FakeLogger9from fixtures import FakeLogger
10import responses
9from testtools import TestCase11from testtools import TestCase
10from testtools.matchers import (12from testtools.matchers import (
11 AnyMatch,13 AnyMatch,
@@ -26,12 +28,17 @@
2628
27class RanCommand(MatchesListwise):29class RanCommand(MatchesListwise):
2830
29 def __init__(self, args, echo=None, cwd=None, **env):31 def __init__(self, args, echo=None, cwd=None, input_text=None,
32 get_output=None, **env):
30 kwargs_matcher = {}33 kwargs_matcher = {}
31 if echo is not None:34 if echo is not None:
32 kwargs_matcher["echo"] = Is(echo)35 kwargs_matcher["echo"] = Is(echo)
33 if cwd:36 if cwd:
34 kwargs_matcher["cwd"] = Equals(cwd)37 kwargs_matcher["cwd"] = Equals(cwd)
38 if input_text:
39 kwargs_matcher["input_text"] = Equals(input_text)
40 if get_output is not None:
41 kwargs_matcher["get_output"] = Is(get_output)
35 if env:42 if env:
36 kwargs_matcher["env"] = MatchesDict(43 kwargs_matcher["env"] = MatchesDict(
37 {key: Equals(value) for key, value in env.items()})44 {key: Equals(value) for key, value in env.items()})
@@ -113,6 +120,36 @@
113 "--install-recommends", "install", "ubuntu-defaults-builder"),120 "--install-recommends", "install", "ubuntu-defaults-builder"),
114 ]))121 ]))
115122
123 @responses.activate
124 def test_install_snap_store_proxy(self):
125 store_assertion = dedent("""\
126 type: store
127 store: store-id
128 url: http://snap-store-proxy.example
129
130 body
131 """)
132
133 def respond(request):
134 return 200, {"X-Assertion-Store-Id": "store-id"}, store_assertion
135
136 responses.add_callback(
137 "GET", "http://snap-store-proxy.example/v2/auth/store/assertions",
138 callback=respond)
139 args = [
140 "buildlivefs",
141 "--backend=fake", "--series=xenial", "--arch=amd64", "1",
142 "--snap-store-proxy-url", "http://snap-store-proxy.example/",
143 ]
144 build_livefs = parse_args(args=args).operation
145 build_livefs.install()
146 self.assertThat(build_livefs.backend.run.calls, MatchesListwise([
147 RanAptGet("install", "livecd-rootfs"),
148 RanCommand(
149 ["snap", "ack", "/dev/stdin"], input_text=store_assertion),
150 RanCommand(["snap", "set", "core", "proxy.store=store-id"]),
151 ]))
152
116 def test_build(self):153 def test_build(self):
117 args = [154 args = [
118 "buildlivefs",155 "buildlivefs",
119156
=== modified file 'lpbuildd/target/tests/test_build_snap.py'
--- lpbuildd/target/tests/test_build_snap.py 2019-05-08 14:52:28 +0000
+++ lpbuildd/target/tests/test_build_snap.py 2019-06-05 14:11:48 +0000
@@ -1,4 +1,4 @@
1# Copyright 2017 Canonical Ltd. This software is licensed under the1# Copyright 2017-2019 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4__metaclass__ = type4__metaclass__ = type
@@ -7,11 +7,13 @@
7import os.path7import os.path
8import stat8import stat
9import subprocess9import subprocess
10from textwrap import dedent
1011
11from fixtures import (12from fixtures import (
12 FakeLogger,13 FakeLogger,
13 TempDir,14 TempDir,
14 )15 )
16import responses
15from systemfixtures import FakeFilesystem17from systemfixtures import FakeFilesystem
16from testtools import TestCase18from testtools import TestCase
17from testtools.matchers import (19from testtools.matchers import (
@@ -33,14 +35,17 @@
3335
34class RanCommand(MatchesListwise):36class RanCommand(MatchesListwise):
3537
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,
39 get_output=None, **env):
37 kwargs_matcher = {}40 kwargs_matcher = {}
38 if get_output is not None:
39 kwargs_matcher["get_output"] = Is(get_output)
40 if echo is not None:41 if echo is not None:
41 kwargs_matcher["echo"] = Is(echo)42 kwargs_matcher["echo"] = Is(echo)
42 if cwd:43 if cwd:
43 kwargs_matcher["cwd"] = Equals(cwd)44 kwargs_matcher["cwd"] = Equals(cwd)
45 if input_text:
46 kwargs_matcher["input_text"] = Equals(input_text)
47 if get_output is not None:
48 kwargs_matcher["get_output"] = Is(get_output)
44 if env:49 if env:
45 kwargs_matcher["env"] = MatchesDict(50 kwargs_matcher["env"] = MatchesDict(
46 {key: Equals(value) for key, value in env.items()})51 {key: Equals(value) for key, value in env.items()})
@@ -132,6 +137,38 @@
132 RanAptGet("install", "git", "snapcraft"),137 RanAptGet("install", "git", "snapcraft"),
133 ]))138 ]))
134139
140 @responses.activate
141 def test_install_snap_store_proxy(self):
142 store_assertion = dedent("""\
143 type: store
144 store: store-id
145 url: http://snap-store-proxy.example
146
147 body
148 """)
149
150 def respond(request):
151 return 200, {"X-Assertion-Store-Id": "store-id"}, store_assertion
152
153 responses.add_callback(
154 "GET", "http://snap-store-proxy.example/v2/auth/store/assertions",
155 callback=respond)
156 args = [
157 "buildsnap",
158 "--backend=fake", "--series=xenial", "--arch=amd64", "1",
159 "--git-repository", "lp:foo",
160 "--snap-store-proxy-url", "http://snap-store-proxy.example/",
161 "test-snap",
162 ]
163 build_snap = parse_args(args=args).operation
164 build_snap.install()
165 self.assertThat(build_snap.backend.run.calls, MatchesListwise([
166 RanAptGet("install", "git", "snapcraft"),
167 RanCommand(
168 ["snap", "ack", "/dev/stdin"], input_text=store_assertion),
169 RanCommand(["snap", "set", "core", "proxy.store=store-id"]),
170 ]))
171
135 def test_install_proxy(self):172 def test_install_proxy(self):
136 args = [173 args = [
137 "buildsnap",174 "buildsnap",
138175
=== modified file 'lpbuildd/tests/fakebuilder.py'
--- lpbuildd/tests/fakebuilder.py 2019-02-12 10:41:20 +0000
+++ lpbuildd/tests/fakebuilder.py 2019-06-05 14:11:48 +0000
@@ -1,4 +1,4 @@
1# Copyright 2013 Canonical Ltd. This software is licensed under the1# Copyright 2013-2019 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4__metaclass__ = type4__metaclass__ = type
@@ -9,12 +9,18 @@
9 'UncontainedBackend',9 'UncontainedBackend',
10 ]10 ]
1111
12from collections import defaultdict
12import hashlib13import hashlib
13import os14import os
14import shutil15import shutil
15import stat16import stat
16import subprocess17import subprocess
1718
19from six.moves.configparser import (
20 NoOptionError,
21 NoSectionError,
22 )
23
18from lpbuildd.target.backend import Backend24from lpbuildd.target.backend import Backend
19from lpbuildd.util import (25from lpbuildd.util import (
20 set_personality,26 set_personality,
@@ -78,8 +84,22 @@
7884
7985
80class FakeConfig:86class FakeConfig:
87 def __init__(self):
88 self._overrides = defaultdict(dict)
89
81 def get(self, section, key):90 def get(self, section, key):
82 return key91 if key in self._overrides[section]:
92 return self._overrides[section][key]
93 elif section == "proxy":
94 if not self._overrides[section]:
95 raise NoSectionError(section)
96 else:
97 raise NoOptionError(section, key)
98 else:
99 return key
100
101 def set(self, section, key, value):
102 self._overrides[section][key] = value
83103
84104
85class FakeBuilder:105class FakeBuilder:
86106
=== modified file 'lpbuildd/tests/test_debian.py'
--- lpbuildd/tests/test_debian.py 2019-02-12 10:41:20 +0000
+++ lpbuildd/tests/test_debian.py 2019-06-05 14:11:48 +0000
@@ -1,4 +1,4 @@
1# Copyright 2017 Canonical Ltd. This software is licensed under the1# Copyright 2017-2019 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4__metaclass__ = type4__metaclass__ = type
@@ -404,6 +404,36 @@
404 self.assertTrue(self.builder.wasCalled('buildOK'))404 self.assertTrue(self.builder.wasCalled('buildOK'))
405 self.assertTrue(self.builder.wasCalled('buildComplete'))405 self.assertTrue(self.builder.wasCalled('buildComplete'))
406406
407 def test_iterate_apt_proxy(self):
408 # The build manager can be configured to use an APT proxy.
409 self.builder._config.set(
410 'proxy', 'apt', 'http://apt-proxy.example:3128/')
411 extra_args = {
412 'arch_tag': 'amd64',
413 'archives': [
414 'deb http://ppa.launchpad.dev/owner/name/ubuntu xenial main',
415 ],
416 'series': 'xenial',
417 }
418 self.startBuild(extra_args)
419
420 self.buildmanager.iterate(0)
421 self.assertEqual(DebianBuildState.UNPACK, self.getState())
422 self.buildmanager.iterate(0)
423 self.assertEqual(DebianBuildState.MOUNT, self.getState())
424 self.buildmanager.iterate(0)
425 self.assertEqual(DebianBuildState.SOURCES, self.getState())
426 self.assertEqual(
427 (['sharepath/bin/in-target', 'in-target', 'override-sources-list',
428 '--backend=chroot', '--series=xenial', '--arch=amd64',
429 self.buildid,
430 '--apt-proxy-url', 'http://apt-proxy.example:3128/',
431 'deb http://ppa.launchpad.dev/owner/name/ubuntu xenial main'],
432 None),
433 self.buildmanager.commands[-1])
434 self.assertEqual(
435 self.buildmanager.iterate, self.buildmanager.iterators[-1])
436
407 def test_iterate_lxd(self):437 def test_iterate_lxd(self):
408 # The build manager passes the image_type argument through to438 # The build manager passes the image_type argument through to
409 # unpack-chroot.439 # unpack-chroot.
410440
=== modified file 'lpbuildd/tests/test_livefs.py'
--- lpbuildd/tests/test_livefs.py 2019-02-12 10:41:20 +0000
+++ lpbuildd/tests/test_livefs.py 2019-06-05 14:11:48 +0000
@@ -1,4 +1,4 @@
1# Copyright 2013-2018 Canonical Ltd. This software is licensed under the1# Copyright 2013-2019 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4__metaclass__ = type4__metaclass__ = type
@@ -58,7 +58,7 @@
58 return self.buildmanager._state58 return self.buildmanager._state
5959
60 @defer.inlineCallbacks60 @defer.inlineCallbacks
61 def startBuild(self):61 def startBuild(self, options=None):
62 # The build manager's iterate() kicks off the consecutive states62 # The build manager's iterate() kicks off the consecutive states
63 # after INIT.63 # after INIT.
64 extra_args = {64 extra_args = {
@@ -85,6 +85,8 @@
85 "--backend=lxd", "--series=saucy", "--arch=i386", self.buildid,85 "--backend=lxd", "--series=saucy", "--arch=i386", self.buildid,
86 "--project", "ubuntu",86 "--project", "ubuntu",
87 ]87 ]
88 if options is not None:
89 expected_command.extend(options)
88 self.assertEqual(expected_command, self.buildmanager.commands[-1])90 self.assertEqual(expected_command, self.buildmanager.commands[-1])
89 self.assertEqual(91 self.assertEqual(
90 self.buildmanager.iterate, self.buildmanager.iterators[-1])92 self.buildmanager.iterate, self.buildmanager.iterators[-1])
@@ -131,6 +133,15 @@
131 self.assertFalse(self.builder.wasCalled("buildFail"))133 self.assertFalse(self.builder.wasCalled("buildFail"))
132134
133 @defer.inlineCallbacks135 @defer.inlineCallbacks
136 def test_iterate_snap_store_proxy(self):
137 # The build manager can be told to use a snap store proxy.
138 self.builder._config.set(
139 "proxy", "snapstore", "http://snap-store-proxy.example/")
140 expected_options = [
141 "--snap-store-proxy-url", "http://snap-store-proxy.example/"]
142 yield self.startBuild(options=expected_options)
143
144 @defer.inlineCallbacks
134 def test_omits_symlinks(self):145 def test_omits_symlinks(self):
135 # Symlinks in the build output are not included in gathered results.146 # Symlinks in the build output are not included in gathered results.
136 yield self.startBuild()147 yield self.startBuild()
137148
=== modified file 'lpbuildd/tests/test_snap.py'
--- lpbuildd/tests/test_snap.py 2019-05-22 17:59:14 +0000
+++ lpbuildd/tests/test_snap.py 2019-06-05 14:11:48 +0000
@@ -1,4 +1,4 @@
1# Copyright 2015-2018 Canonical Ltd. This software is licensed under the1# Copyright 2015-2019 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4__metaclass__ = type4__metaclass__ = type
@@ -377,6 +377,15 @@
377 self.buildmanager.iterate, self.buildmanager.iterators[-1])377 self.buildmanager.iterate, self.buildmanager.iterators[-1])
378 self.assertFalse(self.builder.wasCalled("buildFail"))378 self.assertFalse(self.builder.wasCalled("buildFail"))
379379
380 @defer.inlineCallbacks
381 def test_iterate_snap_store_proxy(self):
382 # The build manager can be told to use a snap store proxy.
383 self.builder._config.set(
384 "proxy", "snapstore", "http://snap-store-proxy.example/")
385 expected_options = [
386 "--snap-store-proxy-url", "http://snap-store-proxy.example/"]
387 yield self.startBuild(options=expected_options)
388
380 def getListenerURL(self, listener):389 def getListenerURL(self, listener):
381 port = listener.getHost().port390 port = listener.getHost().port
382 return b"http://localhost:%d/" % port391 return b"http://localhost:%d/" % port
383392
=== modified file 'setup.py'
--- setup.py 2018-10-25 09:04:12 +0000
+++ setup.py 2019-06-05 14:11:48 +0000
@@ -1,6 +1,6 @@
1#!/usr/bin/env python1#!/usr/bin/env python
22
3# Copyright 2015 Canonical Ltd. All rights reserved.3# Copyright 2015-2019 Canonical Ltd. All rights reserved.
4#4#
5# This file is part of launchpad-buildd.5# This file is part of launchpad-buildd.
6#6#
@@ -59,6 +59,8 @@
59 # causes problems for Launchpad's build system.59 # causes problems for Launchpad's build system.
60 #'python-apt',60 #'python-apt',
61 'python-debian>=0.1.23',61 'python-debian>=0.1.23',
62 'requests',
63 'six',
62 'Twisted',64 'Twisted',
63 'zope.interface',65 'zope.interface',
64 ],66 ],
@@ -69,6 +71,7 @@
69 tests_require=[71 tests_require=[
70 'fixtures',72 'fixtures',
71 'mock',73 'mock',
74 'responses',
72 'systemfixtures',75 'systemfixtures',
73 'testtools',76 'testtools',
74 'txfixtures',77 'txfixtures',

Subscribers

People subscribed via source and target branches

to all changes: