Merge lp:~cjwatson/launchpad-buildd/local-snap-proxy into lp:launchpad-buildd

Proposed by Colin Watson
Status: Merged
Merged at revision: 341
Proposed branch: lp:~cjwatson/launchpad-buildd/local-snap-proxy
Merge into: lp:launchpad-buildd
Diff against target: 598 lines (+370/-41)
10 files modified
buildd-genconfig (+6/-1)
debian/changelog (+4/-0)
debian/control (+1/-0)
debian/postinst (+1/-1)
debian/upgrade-config (+13/-0)
lpbuildd/buildd-slave.tac (+1/-0)
lpbuildd/snap.py (+262/-2)
lpbuildd/target/build_snap.py (+0/-37)
lpbuildd/tests/test_snap.py (+79/-0)
template-buildd-slave.conf (+3/-0)
To merge this branch: bzr merge lp:~cjwatson/launchpad-buildd/local-snap-proxy
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+322545@code.launchpad.net

Commit message

Add a local unauthenticated proxy on port 8222, which proxies through to
the remote authenticated proxy. This should allow running a wider range
of network clients, since some of them apparently don't support
authenticated proxies very well.

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) wrote :
Revision history for this message
Adam Collard (adam-collard) wrote :

drive by review

217. By Colin Watson

Remove dead code.

Revision history for this message
Colin Watson (cjwatson) :
Revision history for this message
Kevin W Monroe (kwmonroe) wrote :

Aside from the merge conflicts, the spirit of this gets a big +1 from me. I'm running into all sorts of trouble with java projects (mvn, ant, ivy, gradle) and their poor support for auth'd proxies. I think an unauth'd alternative would be super useful.

218. By Colin Watson

Merge trunk.

219. By Colin Watson

Drop now-unnecessary compatibility with Twisted < 14.0.0.

Revision history for this message
Brett Sutton (bsutton) wrote :

Just to add my voice.
This is currently blocking a number of apps I'm trying to build in the store plus anyone that uses a remote part for Apache Tomcat with SSL that I've built.

Revision history for this message
William Grant (wgrant) wrote :

This seems to work fine with some manual testing.

However, this won't directly work for snap builds any more: that --proxy-url is going to point to the container rather than the host.

review: Approve (code)
220. By Colin Watson

Merge trunk.

221. By Colin Watson

Build-depend on curl for proxy tests.

222. By Colin Watson

Fix version in upgrade-config.

223. By Colin Watson

Remove duplicate --proxy-url option.

224. By Colin Watson

Point --proxy-url to the LXD host.

225. By Colin Watson

Close LP #1690834 and #1753340.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'buildd-genconfig'
--- buildd-genconfig 2016-12-09 18:04:00 +0000
+++ buildd-genconfig 2018-06-10 12:47:59 +0000
@@ -37,6 +37,11 @@
37 metavar="FILE",37 metavar="FILE",
38 default="/usr/share/launchpad-buildd/template-buildd-slave.conf")38 default="/usr/share/launchpad-buildd/template-buildd-slave.conf")
3939
40parser.add_option("--snap-proxy-port", dest="SNAPPROXYPORT",
41 help="the port the local snap proxy binds to",
42 metavar="PORT",
43 default="8222")
44
40(options, args) = parser.parse_args()45(options, args) = parser.parse_args()
4146
42template = open(options.TEMPLATE, "r").read()47template = open(options.TEMPLATE, "r").read()
@@ -46,6 +51,7 @@
46 "@BINDHOST@": options.BINDHOST,51 "@BINDHOST@": options.BINDHOST,
47 "@ARCHTAG@": options.ARCHTAG,52 "@ARCHTAG@": options.ARCHTAG,
48 "@BINDPORT@": options.BINDPORT,53 "@BINDPORT@": options.BINDPORT,
54 "@SNAPPROXYPORT@": options.SNAPPROXYPORT,
49 }55 }
5056
51for replacement_key in replacements:57for replacement_key in replacements:
@@ -53,4 +59,3 @@
53 replacements[replacement_key])59 replacements[replacement_key])
5460
55print(template.strip())61print(template.strip())
56
5762
=== modified file 'debian/changelog'
--- debian/changelog 2018-06-05 02:06:04 +0000
+++ debian/changelog 2018-06-10 12:47:59 +0000
@@ -10,6 +10,10 @@
10 * Refactor VCS operations from lpbuildd.target.build_snap out to a module10 * Refactor VCS operations from lpbuildd.target.build_snap out to a module
11 that can be used by other targets.11 that can be used by other targets.
12 * Allow checking out a git tag rather than a branch (LP: #1687078).12 * Allow checking out a git tag rather than a branch (LP: #1687078).
13 * Add a local unauthenticated proxy on port 8222, which proxies through to
14 the remote authenticated proxy. This should allow running a wider range
15 of network clients, since some of them apparently don't support
16 authenticated proxies very well (LP: #1690834, #1753340).
1317
14 -- Colin Watson <cjwatson@ubuntu.com> Tue, 08 May 2018 10:36:22 +010018 -- Colin Watson <cjwatson@ubuntu.com> Tue, 08 May 2018 10:36:22 +0100
1519
1620
=== modified file 'debian/control'
--- debian/control 2017-11-27 17:14:19 +0000
+++ debian/control 2018-06-10 12:47:59 +0000
@@ -5,6 +5,7 @@
5Standards-Version: 3.9.55Standards-Version: 3.9.5
6Build-Depends: apt-utils,6Build-Depends: apt-utils,
7 bzr,7 bzr,
8 curl,
8 debhelper (>= 9~),9 debhelper (>= 9~),
9 dh-exec,10 dh-exec,
10 dh-python,11 dh-python,
1112
=== modified file 'debian/postinst'
--- debian/postinst 2017-08-29 13:19:35 +0000
+++ debian/postinst 2018-06-10 12:47:59 +0000
@@ -14,7 +14,7 @@
1414
15make_buildd()15make_buildd()
16{16{
17 /usr/share/launchpad-buildd/buildd-genconfig --name=default --host=0.0.0.0 --port=8221 > \17 /usr/share/launchpad-buildd/buildd-genconfig --name=default --host=0.0.0.0 --port=8221 --snap-proxy-port=8222 > \
18 /etc/launchpad-buildd/default18 /etc/launchpad-buildd/default
19 echo Default buildd created.19 echo Default buildd created.
20}20}
2121
=== modified file 'debian/upgrade-config'
--- debian/upgrade-config 2016-12-09 18:05:21 +0000
+++ debian/upgrade-config 2018-06-10 12:47:59 +0000
@@ -197,6 +197,17 @@
197 in_file.close()197 in_file.close()
198 out_file.close()198 out_file.close()
199199
200def upgrade_to_162():
201 print("Upgrading %s to version 162" % conf_file)
202 os.rename(conf_file, conf_file + "-prev162~")
203
204 with open(conf_file + "-prev162~", "r") as in_file:
205 with open(conf_file, "w") as out_file:
206 out_file.write(in_file.read())
207 out_file.write(
208 "\n[snapmanager]\n"
209 "proxyport = 8222\n")
210
200if __name__ == "__main__":211if __name__ == "__main__":
201 old_version = re.sub(r'[~-].*', '', old_version)212 old_version = re.sub(r'[~-].*', '', old_version)
202 if apt_pkg.version_compare(old_version, "12") < 0:213 if apt_pkg.version_compare(old_version, "12") < 0:
@@ -223,3 +234,5 @@
223 upgrade_to_126()234 upgrade_to_126()
224 if apt_pkg.version_compare(old_version, "127") < 0:235 if apt_pkg.version_compare(old_version, "127") < 0:
225 upgrade_to_127()236 upgrade_to_127()
237 if apt_pkg.version_compare(old_version, "162") < 0:
238 upgrade_to_162()
226239
=== modified file 'lpbuildd/buildd-slave.tac'
--- lpbuildd/buildd-slave.tac 2018-02-27 13:25:36 +0000
+++ lpbuildd/buildd-slave.tac 2018-06-10 12:47:59 +0000
@@ -51,6 +51,7 @@
51application.addComponent(51application.addComponent(
52 RotatableFileLogObserver(options.get('logfile')), ignoreClass=1)52 RotatableFileLogObserver(options.get('logfile')), ignoreClass=1)
53builddslaveService = service.IServiceCollection(application)53builddslaveService = service.IServiceCollection(application)
54slave.slave.service = builddslaveService
5455
55root = resource.Resource()56root = resource.Resource()
56root.putChild('rpc', slave)57root.putChild('rpc', slave)
5758
=== modified file 'lpbuildd/snap.py'
--- lpbuildd/snap.py 2018-04-21 10:04:37 +0000
+++ lpbuildd/snap.py 2018-06-10 12:47:59 +0000
@@ -5,9 +5,39 @@
55
6__metaclass__ = type6__metaclass__ = type
77
8import base64
9import io
8import json10import json
9import os11import os
10import sys12import sys
13try:
14 from urllib.error import (
15 HTTPError,
16 URLError,
17 )
18 from urllib.parse import urlparse
19 from urllib.request import (
20 Request,
21 urlopen,
22 )
23except ImportError:
24 from urllib2 import (
25 HTTPError,
26 Request,
27 URLError,
28 urlopen,
29 )
30 from urlparse import urlparse
31
32from twisted.application import strports
33from twisted.internet import reactor
34from twisted.internet.interfaces import IHalfCloseableProtocol
35from twisted.python.compat import intToBytes
36from twisted.web import (
37 http,
38 proxy,
39 )
40from zope.interface import implementer
1141
12from lpbuildd.debian import (42from lpbuildd.debian import (
13 DebianBuildManager,43 DebianBuildManager,
@@ -21,6 +51,195 @@
21RETCODE_FAILURE_BUILD = 20151RETCODE_FAILURE_BUILD = 201
2252
2353
54class SnapProxyClient(proxy.ProxyClient):
55
56 def __init__(self, command, rest, version, headers, data, father):
57 proxy.ProxyClient.__init__(
58 self, command, rest, version, headers, data, father)
59 # Why doesn't ProxyClient at least store this?
60 self.version = version
61 # We must avoid calling self.father.finish in the event that its
62 # connection was already lost, i.e. if the original client
63 # disconnects first (which is particularly likely in the case of
64 # CONNECT).
65 d = self.father.notifyFinish()
66 d.addBoth(self.requestFinished)
67
68 def connectionMade(self):
69 proxy.ProxyClient.connectionMade(self)
70 self.father.setChildClient(self)
71
72 def sendCommand(self, command, path):
73 # For some reason, HTTPClient.sendCommand doesn't preserve the
74 # protocol version.
75 self.transport.writeSequence(
76 [command, b' ', path, b' ', self.version, b'\r\n'])
77
78 def handleEndHeaders(self):
79 self.father.handleEndHeaders()
80
81 def sendData(self, data):
82 self.transport.write(data)
83
84 def endData(self):
85 if self.transport is not None:
86 self.transport.loseWriteConnection()
87
88 def requestFinished(self, result):
89 self._finished = True
90 self.transport.loseConnection()
91
92
93class SnapProxyClientFactory(proxy.ProxyClientFactory):
94
95 protocol = SnapProxyClient
96
97
98class SnapProxyRequest(http.Request):
99
100 child_client = None
101 _request_buffer = None
102 _request_data_done = False
103
104 def setChildClient(self, child_client):
105 self.child_client = child_client
106 if self._request_buffer is not None:
107 self.child_client.sendData(self._request_buffer.getvalue())
108 self._request_buffer = None
109 if self._request_data_done:
110 self.child_client.endData()
111
112 def allHeadersReceived(self, command, path, version):
113 # Normally done in `requestReceived`, but we disable that since it
114 # does other things we don't want.
115 self.method, self.uri, self.clientproto = command, path, version
116 self.client = self.channel.transport.getPeer()
117 self.host = self.channel.transport.getHost()
118
119 remote_parsed = urlparse(self.channel.factory.remote_url)
120 request_parsed = urlparse(path)
121 headers = self.getAllHeaders().copy()
122 if b"host" not in headers and request_parsed.netloc:
123 headers[b"host"] = request_parsed.netloc
124 if remote_parsed.username:
125 auth = (remote_parsed.username + ":" +
126 remote_parsed.password).encode("ASCII")
127 authHeader = b"Basic " + base64.b64encode(auth)
128 headers[b"proxy-authorization"] = authHeader
129 self.client_factory = SnapProxyClientFactory(
130 command, path, version, headers, b"", self)
131 reactor.connectTCP(
132 remote_parsed.hostname, remote_parsed.port, self.client_factory)
133
134 def requestReceived(self, command, path, version):
135 # We do most of our work in `allHeadersReceived` instead.
136 pass
137
138 def rawDataReceived(self, data):
139 if self.child_client is not None:
140 if not self._request_data_done:
141 self.child_client.sendData(data)
142 else:
143 if self._request_buffer is None:
144 self._request_buffer = io.BytesIO()
145 self._request_buffer.write(data)
146
147 def handleEndHeaders(self):
148 # Cut-down version of Request.write. We must avoid switching to
149 # chunked encoding for the sake of CONNECT; since our actual
150 # response data comes from another proxy, we can cut some corners.
151 if self.startedWriting:
152 return
153 self.startedWriting = 1
154 l = []
155 l.append(
156 self.clientproto + b" " + intToBytes(self.code) + b" " +
157 self.code_message + b"\r\n")
158 for name, values in self.responseHeaders.getAllRawHeaders():
159 for value in values:
160 l.extend([name, b": ", value, b"\r\n"])
161 l.append(b"\r\n")
162 self.transport.writeSequence(l)
163
164 def write(self, data):
165 if self.channel is not None:
166 self.channel.resetTimeout()
167 http.Request.write(self, data)
168
169 def endData(self):
170 if self.child_client is not None:
171 self.child_client.endData()
172 self._request_data_done = True
173
174
175@implementer(IHalfCloseableProtocol)
176class SnapProxy(http.HTTPChannel):
177 """A channel that streams request data.
178
179 The stock HTTPChannel isn't quite suitable for our needs, because it
180 expects to read the entire request data before passing control to the
181 request. This doesn't work well for CONNECT.
182 """
183
184 requestFactory = SnapProxyRequest
185
186 def checkPersistence(self, request, version):
187 # ProxyClient.__init__ forces "Connection: close".
188 return False
189
190 def allHeadersReceived(self):
191 http.HTTPChannel.allHeadersReceived(self)
192 self.requests[-1].allHeadersReceived(
193 self._command, self._path, self._version)
194 if self._command == b"CONNECT":
195 # This is a lie, but we don't want HTTPChannel to decide that
196 # the request is finished just because a CONNECT request
197 # (naturally) has no Content-Length.
198 self.length = -1
199
200 def rawDataReceived(self, data):
201 self.resetTimeout()
202 if self.requests:
203 self.requests[-1].rawDataReceived(data)
204
205 def readConnectionLost(self):
206 for request in self.requests:
207 request.endData()
208
209 def writeConnectionLost(self):
210 pass
211
212
213class SnapProxyFactory(http.HTTPFactory):
214
215 protocol = SnapProxy
216
217 def __init__(self, manager, remote_url, *args, **kwargs):
218 http.HTTPFactory.__init__(self, *args, **kwargs)
219 self.manager = manager
220 self.remote_url = remote_url
221
222 def log(self, request):
223 # Log requests to the build log rather than to Twisted.
224 # Reimplement log formatting because there's no point logging the IP
225 # here.
226 referrer = http._escape(request.getHeader(b"referer") or b"-")
227 agent = http._escape(request.getHeader(b"user-agent") or b"-")
228 line = (
229 u'%(timestamp)s "%(method)s %(uri)s %(protocol)s" '
230 u'%(code)d %(length)s "%(referrer)s" "%(agent)s"\n' % {
231 'timestamp': self._logDateTime,
232 'method': http._escape(request.method),
233 'uri': http._escape(request.uri),
234 'protocol': http._escape(request.clientproto),
235 'code': request.code,
236 'length': request.sentLength or "-",
237 'referrer': referrer,
238 'agent': agent,
239 })
240 self.manager._slave.log(line.encode("UTF-8"))
241
242
24class SnapBuildState(DebianBuildState):243class SnapBuildState(DebianBuildState):
25 BUILD_SNAP = "BUILD_SNAP"244 BUILD_SNAP = "BUILD_SNAP"
26245
@@ -47,9 +266,49 @@
47 self.revocation_endpoint = extra_args.get("revocation_endpoint")266 self.revocation_endpoint = extra_args.get("revocation_endpoint")
48 self.build_source_tarball = extra_args.get(267 self.build_source_tarball = extra_args.get(
49 "build_source_tarball", False)268 "build_source_tarball", False)
269 self.proxy_service = None
50270
51 super(SnapBuildManager, self).initiate(files, chroot, extra_args)271 super(SnapBuildManager, self).initiate(files, chroot, extra_args)
52272
273 def startProxy(self):
274 """Start the local snap proxy, if necessary."""
275 if not self.proxy_url:
276 return []
277 proxy_port = self._slave._config.get("snapmanager", "proxyport")
278 proxy_factory = SnapProxyFactory(self, self.proxy_url, timeout=60)
279 self.proxy_service = strports.service(proxy_port, proxy_factory)
280 self.proxy_service.setServiceParent(self._slave.service)
281 if self.backend_name == "lxd":
282 proxy_host = self.backend.ipv4_network.ip
283 else:
284 proxy_host = "localhost"
285 return ["--proxy-url", "http://{}:{}/".format(proxy_host, proxy_port)]
286
287 def stopProxy(self):
288 """Stop the local snap proxy, if necessary."""
289 if self.proxy_service is None:
290 return
291 self.proxy_service.disownServiceParent()
292 self.proxy_service = None
293
294 def revokeProxyToken(self):
295 """Revoke builder proxy token."""
296 if not self.revocation_endpoint:
297 return
298 self._slave.log("Revoking proxy token...\n")
299 url = urlparse(self.proxy_url)
300 auth = "{}:{}".format(url.username, url.password)
301 headers = {
302 "Authorization": "Basic {}".format(base64.b64encode(auth))
303 }
304 req = Request(self.revocation_endpoint, None, headers)
305 req.get_method = lambda: "DELETE"
306 try:
307 urlopen(req)
308 except (HTTPError, URLError) as e:
309 self._slave.log(
310 "Unable to revoke token for %s: %s" % (url.username, e))
311
53 def status(self):312 def status(self):
54 status_path = get_build_path(self.home, self._buildid, "status")313 status_path = get_build_path(self.home, self._buildid, "status")
55 try:314 try:
@@ -78,8 +337,7 @@
78 file=sys.stderr)337 file=sys.stderr)
79 if self.build_url:338 if self.build_url:
80 args.extend(["--build-url", self.build_url])339 args.extend(["--build-url", self.build_url])
81 if self.proxy_url:340 args.extend(self.startProxy())
82 args.extend(["--proxy-url", self.proxy_url])
83 if self.revocation_endpoint:341 if self.revocation_endpoint:
84 args.extend(["--revocation-endpoint", self.revocation_endpoint])342 args.extend(["--revocation-endpoint", self.revocation_endpoint])
85 if self.branch is not None:343 if self.branch is not None:
@@ -95,6 +353,8 @@
95353
96 def iterate_BUILD_SNAP(self, retcode):354 def iterate_BUILD_SNAP(self, retcode):
97 """Finished building the snap."""355 """Finished building the snap."""
356 self.stopProxy()
357 self.revokeProxyToken()
98 if retcode == RETCODE_SUCCESS:358 if retcode == RETCODE_SUCCESS:
99 self.gatherResults()359 self.gatherResults()
100 print("Returning build status: OK")360 print("Returning build status: OK")
101361
=== modified file 'lpbuildd/target/build_snap.py'
--- lpbuildd/target/build_snap.py 2018-06-05 02:06:04 +0000
+++ lpbuildd/target/build_snap.py 2018-06-10 12:47:59 +0000
@@ -5,30 +5,11 @@
55
6__metaclass__ = type6__metaclass__ = type
77
8import base64
9from collections import OrderedDict8from collections import OrderedDict
10import json9import json
11import logging10import logging
12import os.path11import os.path
13import sys12import sys
14try:
15 from urllib.error import (
16 HTTPError,
17 URLError,
18 )
19 from urllib.request import (
20 Request,
21 urlopen,
22 )
23 from urllib.parse import urlparse
24except ImportError:
25 from urllib2 import (
26 HTTPError,
27 Request,
28 URLError,
29 urlopen,
30 )
31 from urlparse import urlparse
3213
33from lpbuildd.target.operation import Operation14from lpbuildd.target.operation import Operation
34from lpbuildd.target.vcs import VCSOperationMixin15from lpbuildd.target.vcs import VCSOperationMixin
@@ -206,21 +187,6 @@
206 cwd=os.path.join("/build", self.args.name),187 cwd=os.path.join("/build", self.args.name),
207 env=env)188 env=env)
208189
209 def revoke_token(self):
210 """Revoke builder proxy token."""
211 logger.info("Revoking proxy token...")
212 url = urlparse(self.args.proxy_url)
213 auth = '{}:{}'.format(url.username, url.password)
214 headers = {
215 'Authorization': 'Basic {}'.format(base64.b64encode(auth))
216 }
217 req = Request(self.args.revocation_endpoint, None, headers)
218 req.get_method = lambda: 'DELETE'
219 try:
220 urlopen(req)
221 except (HTTPError, URLError):
222 logger.exception('Unable to revoke token for %s', url.username)
223
224 def run(self):190 def run(self):
225 try:191 try:
226 self.install()192 self.install()
@@ -234,7 +200,4 @@
234 except Exception:200 except Exception:
235 logger.exception('Build failed')201 logger.exception('Build failed')
236 return RETCODE_FAILURE_BUILD202 return RETCODE_FAILURE_BUILD
237 finally:
238 if self.args.revocation_endpoint is not None:
239 self.revoke_token()
240 return 0203 return 0
241204
=== modified file 'lpbuildd/tests/test_snap.py'
--- lpbuildd/tests/test_snap.py 2018-04-21 10:04:00 +0000
+++ lpbuildd/tests/test_snap.py 2018-06-10 12:47:59 +0000
@@ -10,10 +10,25 @@
10 TempDir,10 TempDir,
11 )11 )
12from testtools import TestCase12from testtools import TestCase
13from testtools.content import text_content
14from testtools.deferredruntest import AsynchronousDeferredRunTest
15from twisted.internet import (
16 defer,
17 reactor,
18 utils,
19 )
20from twisted.web import (
21 http,
22 proxy,
23 resource,
24 server,
25 static,
26 )
1327
14from lpbuildd.snap import (28from lpbuildd.snap import (
15 SnapBuildManager,29 SnapBuildManager,
16 SnapBuildState,30 SnapBuildState,
31 SnapProxyFactory,
17 )32 )
18from lpbuildd.tests.fakeslave import FakeSlave33from lpbuildd.tests.fakeslave import FakeSlave
19from lpbuildd.tests.matchers import HasWaitingFiles34from lpbuildd.tests.matchers import HasWaitingFiles
@@ -35,6 +50,9 @@
3550
36class TestSnapBuildManagerIteration(TestCase):51class TestSnapBuildManagerIteration(TestCase):
37 """Run SnapBuildManager through its iteration steps."""52 """Run SnapBuildManager through its iteration steps."""
53
54 run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=5)
55
38 def setUp(self):56 def setUp(self):
39 super(TestSnapBuildManagerIteration, self).setUp()57 super(TestSnapBuildManagerIteration, self).setUp()
40 self.working_dir = self.useFixture(TempDir()).path58 self.working_dir = self.useFixture(TempDir()).path
@@ -229,3 +247,64 @@
229 self.assertEqual(247 self.assertEqual(
230 self.buildmanager.iterate, self.buildmanager.iterators[-1])248 self.buildmanager.iterate, self.buildmanager.iterators[-1])
231 self.assertFalse(self.slave.wasCalled("buildFail"))249 self.assertFalse(self.slave.wasCalled("buildFail"))
250
251 def getListenerURL(self, listener):
252 port = listener.getHost().port
253 return b"http://localhost:%d/" % port
254
255 def startFakeRemoteEndpoint(self):
256 remote_endpoint = resource.Resource()
257 remote_endpoint.putChild("a", static.Data("a" * 1024, "text/plain"))
258 remote_endpoint.putChild("b", static.Data("b" * 65536, "text/plain"))
259 remote_endpoint_listener = reactor.listenTCP(
260 0, server.Site(remote_endpoint))
261 self.addCleanup(remote_endpoint_listener.stopListening)
262 return remote_endpoint_listener
263
264 def startFakeRemoteProxy(self):
265 remote_proxy_factory = http.HTTPFactory()
266 remote_proxy_factory.protocol = proxy.Proxy
267 remote_proxy_listener = reactor.listenTCP(0, remote_proxy_factory)
268 self.addCleanup(remote_proxy_listener.stopListening)
269 return remote_proxy_listener
270
271 def startLocalProxy(self, remote_url):
272 proxy_factory = SnapProxyFactory(
273 self.buildmanager, remote_url, timeout=60)
274 proxy_listener = reactor.listenTCP(0, proxy_factory)
275 self.addCleanup(proxy_listener.stopListening)
276 return proxy_listener
277
278 @defer.inlineCallbacks
279 def assertCommandSuccess(self, command, extra_env=None):
280 env = os.environ
281 if extra_env is not None:
282 env.update(extra_env)
283 out, err, code = yield utils.getProcessOutputAndValue(
284 command[0], command[1:], env=env, path=".")
285 if code != 0:
286 self.addDetail("stdout", text_content(out))
287 self.addDetail("stderr", text_content(err))
288 self.assertEqual(0, code)
289 defer.returnValue(out)
290
291 @defer.inlineCallbacks
292 def test_fetch_via_proxy(self):
293 remote_endpoint_listener = self.startFakeRemoteEndpoint()
294 remote_endpoint_url = self.getListenerURL(remote_endpoint_listener)
295 remote_proxy_listener = self.startFakeRemoteProxy()
296 proxy_listener = self.startLocalProxy(
297 self.getListenerURL(remote_proxy_listener))
298 out = yield self.assertCommandSuccess(
299 [b"curl", remote_endpoint_url + b"a"],
300 extra_env={b"http_proxy": self.getListenerURL(proxy_listener)})
301 self.assertEqual("a" * 1024, out)
302 out = yield self.assertCommandSuccess(
303 [b"curl", remote_endpoint_url + b"b"],
304 extra_env={b"http_proxy": self.getListenerURL(proxy_listener)})
305 self.assertEqual("b" * 65536, out)
306
307 # XXX cjwatson 2017-04-13: We should really test the HTTPS case as well,
308 # but it's hard to see how to test that in a way that's independent of
309 # the code under test since the stock twisted.web.proxy doesn't support
310 # CONNECT.
232311
=== modified file 'template-buildd-slave.conf'
--- template-buildd-slave.conf 2015-05-11 06:09:19 +0000
+++ template-buildd-slave.conf 2018-06-10 12:47:59 +0000
@@ -12,3 +12,6 @@
1212
13[translationtemplatesmanager]13[translationtemplatesmanager]
14resultarchive = translation-templates.tar.gz14resultarchive = translation-templates.tar.gz
15
16[snapmanager]
17proxyport = @SNAPPROXYPORT@

Subscribers

People subscribed via source and target branches

to all changes: