Colin Watson has proposed merging ~cjwatson/launchpad:rename-builder-proxy into launchpad:master.
Commit message: Rename "snap proxy" to "builder proxy" Requested reviews: Launchpad code reviewers (launchpad-reviewers) For more details, see: https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/406006 It's used for several different build types nowadays, and is too easily confused with the snap store proxy. The XML-RPC protocol between Launchpad and launchpad-buildd remains unchanged, but the builder_proxy_* configuration items in [snappy] are now deprecated and should be moved to [builddmaster]. -- Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:rename-builder-proxy into launchpad:master.
diff --git a/configs/development/launchpad-lazr.conf b/configs/development/launchpad-lazr.conf index 2b41199..138714d 100644 --- a/configs/development/launchpad-lazr.conf +++ b/configs/development/launchpad-lazr.conf @@ -13,6 +13,10 @@ root: /var/tmp/builddmaster/ uploader: scripts/process-upload.py -Mvv bzr_builder_sources_list: None authentication_endpoint: http://xmlrpc-private.launchpad.test:8087/authserver +builder_proxy_auth_api_admin_username: admin-launchpad.test +builder_proxy_auth_api_endpoint: http://builder-proxy.launchpad.test:8080/tokens +builder_proxy_host: builder-proxy.launchpad.test +builder_proxy_port: 3128 [canonical] show_tracebacks: True @@ -168,10 +172,6 @@ password: guest virtual_host: / [snappy] -builder_proxy_auth_api_admin_username: admin-launchpad.test -builder_proxy_auth_api_endpoint: http://snap-proxy.launchpad.test:8080/tokens -builder_proxy_host: snap-proxy.launchpad.test -builder_proxy_port: 3128 store_search_url: https://api.snapcraft.io/ tools_source: deb http://ppa.launchpad.net/snappy-dev/snapcraft-daily/ubuntu %(series)s main diff --git a/lib/lp/buildmaster/builderproxy.py b/lib/lp/buildmaster/builderproxy.py new file mode 100644 index 0000000..6b1e7e0 --- /dev/null +++ b/lib/lp/buildmaster/builderproxy.py @@ -0,0 +1,80 @@ +# Copyright 2015-2021 Canonical Ltd. This software is licensed under the +# GNU Affero General Public License version 3 (see the file LICENSE). + +"""Builder proxy support. + +Some build types require general internet access; others require that +general internet access not be available (for reproducibility, auditability, +and so on). To resolve this dilemma, the build farm may include an +authenticated proxy; we provide builds with the necessary authentication +token if and only if they are allowed general internet access. +""" + +from __future__ import absolute_import, print_function, unicode_literals + +__metaclass__ = type +__all__ = [ + "BuilderProxyMixin", + ] + +import base64 +import time + +from twisted.internet import defer + +from lp.buildmaster.downloader import RequestProxyTokenCommand +from lp.buildmaster.interfaces.builder import CannotBuild +from lp.services.config import config + + +def _get_proxy_config(name): + """Get a config item from builddmaster (current) or snappy (deprecated).""" + return getattr(config.builddmaster, name) or getattr(config.snappy, name) + + +class BuilderProxyMixin: + """Methods for handling builds with the Snap Build Proxy enabled.""" + + @defer.inlineCallbacks + def addProxyArgs(self, args, allow_internet=True): + if _get_proxy_config("builder_proxy_host") and allow_internet: + token = yield self._requestProxyToken() + args["proxy_url"] = ( + "http://{username}:{password}@{host}:{port}".format( + username=token['username'], + password=token['secret'], + host=_get_proxy_config("builder_proxy_host"), + port=_get_proxy_config("builder_proxy_port"))) + args["revocation_endpoint"] = ( + "{endpoint}/{token}".format( + endpoint=_get_proxy_config( + "builder_proxy_auth_api_endpoint"), + token=token['username'])) + + @defer.inlineCallbacks + def _requestProxyToken(self): + admin_username = _get_proxy_config( + "builder_proxy_auth_api_admin_username") + if not admin_username: + raise CannotBuild( + "builder_proxy_auth_api_admin_username is not configured.") + secret = _get_proxy_config("builder_proxy_auth_api_admin_secret") + if not secret: + raise CannotBuild( + "builder_proxy_auth_api_admin_secret is not configured.") + url = _get_proxy_config("builder_proxy_auth_api_endpoint") + if not secret: + raise CannotBuild( + "builder_proxy_auth_api_endpoint is not configured.") + timestamp = int(time.time()) + proxy_username = '{build_id}-{timestamp}'.format( + build_id=self.build.build_cookie, + timestamp=timestamp) + auth_string = '{}:{}'.format(admin_username, secret).strip() + auth_header = b'Basic ' + base64.b64encode(auth_string.encode('ASCII')) + + token = yield self._slave.process_pool.doWork( + RequestProxyTokenCommand, + url=url, auth_header=auth_header, + proxy_username=proxy_username) + defer.returnValue(token) diff --git a/lib/lp/buildmaster/tests/snapbuildproxy.py b/lib/lp/buildmaster/tests/builderproxy.py similarity index 93% rename from lib/lp/buildmaster/tests/snapbuildproxy.py rename to lib/lp/buildmaster/tests/builderproxy.py index f0b0054..4c9a326 100644 --- a/lib/lp/buildmaster/tests/snapbuildproxy.py +++ b/lib/lp/buildmaster/tests/builderproxy.py @@ -1,7 +1,7 @@ # Copyright 2015-2019 Canonical Ltd. This software is licensed under the # GNU Affero General Public License version 3 (see the file LICENSE). -"""Fixtures for dealing with the build time 'snap' HTTP proxy.""" +"""Fixtures for dealing with the build time HTTP proxy.""" from __future__ import absolute_import, print_function, unicode_literals @@ -88,7 +88,7 @@ class InProcessProxyAuthAPIFixture(fixtures.Fixture): port = yield endpoint.listen(site) self.addCleanup(port.stopListening) config.push("in-process-proxy-auth-api-fixture", dedent(""" - [snappy] + [builddmaster] builder_proxy_auth_api_admin_secret: admin-secret builder_proxy_auth_api_endpoint: http://%s:%s/tokens """) % @@ -97,7 +97,7 @@ class InProcessProxyAuthAPIFixture(fixtures.Fixture): class ProxyURLMatcher(MatchesStructure): - """Check that a string is a valid url for a snap build proxy.""" + """Check that a string is a valid url for a builder proxy.""" def __init__(self, job, now): super(ProxyURLMatcher, self).__init__( @@ -105,8 +105,8 @@ class ProxyURLMatcher(MatchesStructure): username=Equals("{}-{}".format( job.build.build_cookie, int(now))), password=HasLength(32), - hostname=Equals(config.snappy.builder_proxy_host), - port=Equals(config.snappy.builder_proxy_port), + hostname=Equals(config.builddmaster.builder_proxy_host), + port=Equals(config.builddmaster.builder_proxy_port), path=Equals("")) def match(self, matchee): @@ -119,5 +119,5 @@ class RevocationEndpointMatcher(Equals): def __init__(self, job, now): super(RevocationEndpointMatcher, self).__init__( "{}/{}-{}".format( - config.snappy.builder_proxy_auth_api_endpoint, + config.builddmaster.builder_proxy_auth_api_endpoint, job.build.build_cookie, int(now))) diff --git a/lib/lp/charms/model/charmrecipebuildbehaviour.py b/lib/lp/charms/model/charmrecipebuildbehaviour.py index cb17e13..e66545b 100644 --- a/lib/lp/charms/model/charmrecipebuildbehaviour.py +++ b/lib/lp/charms/model/charmrecipebuildbehaviour.py @@ -18,6 +18,7 @@ from zope.component import adapter from zope.interface import implementer from zope.security.proxy import removeSecurityProxy +from lp.buildmaster.builderproxy import BuilderProxyMixin from lp.buildmaster.enums import BuildBaseImageType from lp.buildmaster.interfaces.builder import CannotBuild from lp.buildmaster.interfaces.buildfarmjobbehaviour import ( @@ -28,7 +29,6 @@ from lp.buildmaster.model.buildfarmjobbehaviour import ( ) from lp.charms.interfaces.charmrecipebuild import ICharmRecipeBuild from lp.registry.interfaces.series import SeriesStatus -from lp.snappy.model.snapbuildbehaviour import SnapProxyMixin from lp.soyuz.adapters.archivedependencies import ( get_sources_list_for_building, ) @@ -36,7 +36,7 @@ from lp.soyuz.adapters.archivedependencies import ( @adapter(ICharmRecipeBuild) @implementer(IBuildFarmJobBehaviour) -class CharmRecipeBuildBehaviour(SnapProxyMixin, BuildFarmJobBehaviourBase): +class CharmRecipeBuildBehaviour(BuilderProxyMixin, BuildFarmJobBehaviourBase): """Dispatches `CharmRecipeBuild` jobs to slaves.""" builder_type = "charm" diff --git a/lib/lp/charms/tests/test_charmrecipebuildbehaviour.py b/lib/lp/charms/tests/test_charmrecipebuildbehaviour.py index ebd43e4..16c9dad 100644 --- a/lib/lp/charms/tests/test_charmrecipebuildbehaviour.py +++ b/lib/lp/charms/tests/test_charmrecipebuildbehaviour.py @@ -49,16 +49,16 @@ from lp.buildmaster.interfaces.buildfarmjobbehaviour import ( IBuildFarmJobBehaviour, ) from lp.buildmaster.interfaces.processor import IProcessorSet +from lp.buildmaster.tests.builderproxy import ( + InProcessProxyAuthAPIFixture, + ProxyURLMatcher, + RevocationEndpointMatcher, + ) from lp.buildmaster.tests.mock_slaves import ( MockBuilder, OkSlave, SlaveTestHelpers, ) -from lp.buildmaster.tests.snapbuildproxy import ( - InProcessProxyAuthAPIFixture, - ProxyURLMatcher, - RevocationEndpointMatcher, - ) from lp.buildmaster.tests.test_buildfarmjobbehaviour import ( TestGetUploadMethodsMixin, TestHandleStatusMixin, @@ -187,8 +187,8 @@ class TestAsyncCharmRecipeBuildBehaviour( "@{host}:{port}".format( username=self.token['username'], password=self.token['secret'], - host=config.snappy.builder_proxy_host, - port=config.snappy.builder_proxy_port)) + host=config.builddmaster.builder_proxy_host, + port=config.builddmaster.builder_proxy_port)) self.proxy_api = self.useFixture(InProcessProxyAuthAPIFixture()) yield self.proxy_api.start() self.now = time.time() @@ -223,7 +223,8 @@ class TestAsyncCharmRecipeBuildBehaviour( @defer.inlineCallbacks def test_requestProxyToken_unconfigured(self): - self.pushConfig("snappy", builder_proxy_auth_api_admin_secret=None) + self.pushConfig( + "builddmaster", builder_proxy_auth_api_admin_secret=None) job = self.makeJob() expected_exception_msg = ( "builder_proxy_auth_api_admin_secret is not configured.") @@ -235,7 +236,8 @@ class TestAsyncCharmRecipeBuildBehaviour( job = self.makeJob() yield job.extraBuildArgs() expected_uri = urlsplit( - config.snappy.builder_proxy_auth_api_endpoint).path.encode("UTF-8") + config.builddmaster.builder_proxy_auth_api_endpoint + ).path.encode("UTF-8") self.assertThat(self.proxy_api.tokens.requests, MatchesListwise([ MatchesDict({ "method": Equals(b"POST"), @@ -422,7 +424,7 @@ class TestAsyncCharmRecipeBuildBehaviour( @defer.inlineCallbacks def test_dispatchBuildToSlave_prefers_lxd(self): - self.pushConfig("snappy", builder_proxy_host=None) + self.pushConfig("builddmaster", builder_proxy_host=None) job = self.makeJob() builder = MockBuilder() builder.processor = job.build.processor @@ -445,7 +447,7 @@ class TestAsyncCharmRecipeBuildBehaviour( @defer.inlineCallbacks def test_dispatchBuildToSlave_falls_back_to_chroot(self): - self.pushConfig("snappy", builder_proxy_host=None) + self.pushConfig("builddmaster", builder_proxy_host=None) job = self.makeJob() builder = MockBuilder() builder.processor = job.build.processor diff --git a/lib/lp/oci/model/ocirecipebuildbehaviour.py b/lib/lp/oci/model/ocirecipebuildbehaviour.py index a8737f2..86ecceb 100644 --- a/lib/lp/oci/model/ocirecipebuildbehaviour.py +++ b/lib/lp/oci/model/ocirecipebuildbehaviour.py @@ -24,6 +24,7 @@ from zope.component import getUtility from zope.interface import implementer from zope.security.proxy import removeSecurityProxy +from lp.buildmaster.builderproxy import BuilderProxyMixin from lp.buildmaster.enums import BuildBaseImageType from lp.buildmaster.interfaces.builder import ( BuildDaemonError, @@ -41,14 +42,13 @@ from lp.services.config import config from lp.services.librarian.utils import copy_and_close from lp.services.twistedsupport import cancel_on_timeout from lp.services.webapp import canonical_url -from lp.snappy.model.snapbuildbehaviour import SnapProxyMixin from lp.soyuz.adapters.archivedependencies import ( get_sources_list_for_building, ) @implementer(IBuildFarmJobBehaviour) -class OCIRecipeBuildBehaviour(SnapProxyMixin, BuildFarmJobBehaviourBase): +class OCIRecipeBuildBehaviour(BuilderProxyMixin, BuildFarmJobBehaviourBase): builder_type = "oci" image_types = [BuildBaseImageType.LXD, BuildBaseImageType.CHROOT] diff --git a/lib/lp/oci/tests/test_ocirecipebuildbehaviour.py b/lib/lp/oci/tests/test_ocirecipebuildbehaviour.py index 21fc34e..a7058d4 100644 --- a/lib/lp/oci/tests/test_ocirecipebuildbehaviour.py +++ b/lib/lp/oci/tests/test_ocirecipebuildbehaviour.py @@ -60,17 +60,17 @@ from lp.buildmaster.interfaces.buildfarmjobbehaviour import ( IBuildFarmJobBehaviour, ) from lp.buildmaster.interfaces.processor import IProcessorSet +from lp.buildmaster.tests.builderproxy import ( + InProcessProxyAuthAPIFixture, + ProxyURLMatcher, + RevocationEndpointMatcher, + ) from lp.buildmaster.tests.mock_slaves import ( MockBuilder, OkSlave, SlaveTestHelpers, WaitingSlave, ) -from lp.buildmaster.tests.snapbuildproxy import ( - InProcessProxyAuthAPIFixture, - ProxyURLMatcher, - RevocationEndpointMatcher, - ) from lp.buildmaster.tests.test_buildfarmjobbehaviour import ( TestGetUploadMethodsMixin, ) @@ -177,8 +177,8 @@ class TestAsyncOCIRecipeBuildBehaviour( "@{host}:{port}".format( username=self.token['username'], password=self.token['secret'], - host=config.snappy.builder_proxy_host, - port=config.snappy.builder_proxy_port)) + host=config.builddmaster.builder_proxy_host, + port=config.builddmaster.builder_proxy_port)) self.proxy_api = self.useFixture(InProcessProxyAuthAPIFixture()) yield self.proxy_api.start() self.now = time.time() @@ -223,7 +223,8 @@ class TestAsyncOCIRecipeBuildBehaviour( @defer.inlineCallbacks def test_requestProxyToken_unconfigured(self): - self.pushConfig("snappy", builder_proxy_auth_api_admin_secret=None) + self.pushConfig( + "builddmaster", builder_proxy_auth_api_admin_secret=None) [ref] = self.factory.makeGitRefs() job = self.makeJob(git_ref=ref) expected_exception_msg = ( @@ -237,7 +238,8 @@ class TestAsyncOCIRecipeBuildBehaviour( job = self.makeJob(git_ref=ref) yield job.extraBuildArgs() expected_uri = urlsplit( - config.snappy.builder_proxy_auth_api_endpoint).path.encode("UTF-8") + config.builddmaster.builder_proxy_auth_api_endpoint + ).path.encode("UTF-8") self.assertThat(self.proxy_api.tokens.requests, MatchesListwise([ MatchesDict({ "method": Equals(b"POST"), @@ -588,7 +590,7 @@ class TestAsyncOCIRecipeBuildBehaviour( @defer.inlineCallbacks def test_dispatchBuildToSlave_prefers_lxd(self): - self.pushConfig("snappy", builder_proxy_host=None) + self.pushConfig("builddmaster", builder_proxy_host=None) [ref] = self.factory.makeGitRefs() job = self.makeJob(git_ref=ref, allow_internet=False) builder = MockBuilder() @@ -613,7 +615,7 @@ class TestAsyncOCIRecipeBuildBehaviour( @defer.inlineCallbacks def test_dispatchBuildToSlave_falls_back_to_chroot(self): - self.pushConfig("snappy", builder_proxy_host=None) + self.pushConfig("builddmaster", builder_proxy_host=None) [ref] = self.factory.makeGitRefs() job = self.makeJob(git_ref=ref, allow_internet=False) builder = MockBuilder() @@ -629,7 +631,7 @@ class TestAsyncOCIRecipeBuildBehaviour( @defer.inlineCallbacks def test_dispatchBuildToSlave_oci_feature_flag_enabled(self): - self.pushConfig("snappy", builder_proxy_host=None) + self.pushConfig("builddmaster", builder_proxy_host=None) [ref] = self.factory.makeGitRefs() distribution = self.factory.makeDistribution() diff --git a/lib/lp/services/config/schema-lazr.conf b/lib/lp/services/config/schema-lazr.conf index 8bdc3f1..2b387cb 100644 --- a/lib/lp/services/config/schema-lazr.conf +++ b/lib/lp/services/config/schema-lazr.conf @@ -113,6 +113,23 @@ authentication_endpoint: none # authserver. authentication_timeout: 15 +# Admin secret for requesting tokens from the builder proxy service. +# For a mojo deployed proxy service, the secret is generated and will reside in +# /srv/mojo/${MOJO_PROJECT}/${SERIES}/${MOJO_WORKSPACE}/local/admin-api-secret +builder_proxy_auth_api_admin_secret: none + +# Admin username for builder proxy service. +builder_proxy_auth_api_admin_username: none + +# Endpoint for builder proxy authentication service +builder_proxy_auth_api_endpoint: none + +# Builder http proxy host +builder_proxy_host: none + +# Builder http proxy port +builder_proxy_port: none + [canonical] # datatype: boolean show_tracebacks: False @@ -1755,18 +1772,23 @@ auto_build_frequency: 60 # Admin secret for requesting tokens from the builder proxy service. # For a mojo deployed proxy service, the secret is generated and will reside in # /srv/mojo/${MOJO_PROJECT}/${SERIES}/${MOJO_WORKSPACE}/local/admin-api-secret +# Deprecated in favour of the same key in the builddmaster section. builder_proxy_auth_api_admin_secret: none # Admin username for builder proxy service. +# Deprecated in favour of the same key in the builddmaster section. builder_proxy_auth_api_admin_username: none # Endpoint for builder proxy authentication service +# Deprecated in favour of the same key in the builddmaster section. builder_proxy_auth_api_endpoint: none # Builder http proxy host +# Deprecated in favour of the same key in the builddmaster section. builder_proxy_host: none # Builder http proxy port +# Deprecated in favour of the same key in the builddmaster section. builder_proxy_port: none # Optional sources.list entry to send to build slaves when doing snap diff --git a/lib/lp/snappy/model/snapbuildbehaviour.py b/lib/lp/snappy/model/snapbuildbehaviour.py index 0057670..09a9162 100644 --- a/lib/lp/snappy/model/snapbuildbehaviour.py +++ b/lib/lp/snappy/model/snapbuildbehaviour.py @@ -11,18 +11,14 @@ from __future__ import absolute_import, print_function, unicode_literals __metaclass__ = type __all__ = [ 'SnapBuildBehaviour', - 'SnapProxyMixin', ] -import base64 -import time - from twisted.internet import defer from zope.component import adapter from zope.interface import implementer from zope.security.proxy import removeSecurityProxy -from lp.buildmaster.downloader import RequestProxyTokenCommand +from lp.buildmaster.builderproxy import BuilderProxyMixin from lp.buildmaster.enums import BuildBaseImageType from lp.buildmaster.interfaces.builder import CannotBuild from lp.buildmaster.interfaces.buildfarmjobbehaviour import ( @@ -57,55 +53,9 @@ def format_as_rfc3339(timestamp): return timestamp.replace(microsecond=0, tzinfo=None).isoformat() + 'Z' -class SnapProxyMixin: - """Methods for handling builds with the Snap Build Proxy enabled.""" - - @defer.inlineCallbacks - def addProxyArgs(self, args, allow_internet=True): - if config.snappy.builder_proxy_host and allow_internet: - token = yield self._requestProxyToken() - args["proxy_url"] = ( - "http://{username}:{password}@{host}:{port}".format( - username=token['username'], - password=token['secret'], - host=config.snappy.builder_proxy_host, - port=config.snappy.builder_proxy_port)) - args["revocation_endpoint"] = ( - "{endpoint}/{token}".format( - endpoint=config.snappy.builder_proxy_auth_api_endpoint, - token=token['username'])) - - @defer.inlineCallbacks - def _requestProxyToken(self): - admin_username = config.snappy.builder_proxy_auth_api_admin_username - if not admin_username: - raise CannotBuild( - "builder_proxy_auth_api_admin_username is not configured.") - secret = config.snappy.builder_proxy_auth_api_admin_secret - if not secret: - raise CannotBuild( - "builder_proxy_auth_api_admin_secret is not configured.") - url = config.snappy.builder_proxy_auth_api_endpoint - if not secret: - raise CannotBuild( - "builder_proxy_auth_api_endpoint is not configured.") - timestamp = int(time.time()) - proxy_username = '{build_id}-{timestamp}'.format( - build_id=self.build.build_cookie, - timestamp=timestamp) - auth_string = '{}:{}'.format(admin_username, secret).strip() - auth_header = b'Basic ' + base64.b64encode(auth_string.encode('ASCII')) - - token = yield self._slave.process_pool.doWork( - RequestProxyTokenCommand, - url=url, auth_header=auth_header, - proxy_username=proxy_username) - defer.returnValue(token) - - @adapter(ISnapBuild) @implementer(IBuildFarmJobBehaviour) -class SnapBuildBehaviour(SnapProxyMixin, BuildFarmJobBehaviourBase): +class SnapBuildBehaviour(BuilderProxyMixin, BuildFarmJobBehaviourBase): """Dispatches `SnapBuild` jobs to slaves.""" builder_type = "snap" diff --git a/lib/lp/snappy/tests/test_snapbuildbehaviour.py b/lib/lp/snappy/tests/test_snapbuildbehaviour.py index 0deebed..11462de 100644 --- a/lib/lp/snappy/tests/test_snapbuildbehaviour.py +++ b/lib/lp/snappy/tests/test_snapbuildbehaviour.py @@ -54,16 +54,16 @@ from lp.buildmaster.interfaces.buildfarmjobbehaviour import ( IBuildFarmJobBehaviour, ) from lp.buildmaster.interfaces.processor import IProcessorSet +from lp.buildmaster.tests.builderproxy import ( + InProcessProxyAuthAPIFixture, + ProxyURLMatcher, + RevocationEndpointMatcher, + ) from lp.buildmaster.tests.mock_slaves import ( MockBuilder, OkSlave, SlaveTestHelpers, ) -from lp.buildmaster.tests.snapbuildproxy import ( - InProcessProxyAuthAPIFixture, - ProxyURLMatcher, - RevocationEndpointMatcher, - ) from lp.buildmaster.tests.test_buildfarmjobbehaviour import ( TestGetUploadMethodsMixin, TestHandleStatusMixin, @@ -264,8 +264,8 @@ class TestAsyncSnapBuildBehaviour(StatsMixin, TestSnapBuildBehaviourBase): "@{host}:{port}".format( username=self.token['username'], password=self.token['secret'], - host=config.snappy.builder_proxy_host, - port=config.snappy.builder_proxy_port)) + host=config.builddmaster.builder_proxy_host, + port=config.builddmaster.builder_proxy_port)) self.proxy_api = self.useFixture(InProcessProxyAuthAPIFixture()) yield self.proxy_api.start() self.now = time.time() @@ -301,7 +301,8 @@ class TestAsyncSnapBuildBehaviour(StatsMixin, TestSnapBuildBehaviourBase): @defer.inlineCallbacks def test_requestProxyToken_unconfigured(self): - self.pushConfig("snappy", builder_proxy_auth_api_admin_secret=None) + self.pushConfig( + "builddmaster", builder_proxy_auth_api_admin_secret=None) branch = self.factory.makeBranch() job = self.makeJob(branch=branch) expected_exception_msg = ( @@ -315,7 +316,8 @@ class TestAsyncSnapBuildBehaviour(StatsMixin, TestSnapBuildBehaviourBase): job = self.makeJob(branch=branch) yield job.extraBuildArgs() expected_uri = urlsplit( - config.snappy.builder_proxy_auth_api_endpoint).path.encode("UTF-8") + config.builddmaster.builder_proxy_auth_api_endpoint + ).path.encode("UTF-8") self.assertThat(self.proxy_api.tokens.requests, MatchesListwise([ MatchesDict({ "method": Equals(b"POST"),
_______________________________________________ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : [email protected] Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp

