Merge lp:~cjwatson/launchpad/global-urlfetch-timeout into lp:launchpad

Proposed by Colin Watson
Status: Merged
Merged at revision: 18910
Proposed branch: lp:~cjwatson/launchpad/global-urlfetch-timeout
Merge into: lp:launchpad
Diff against target: 145 lines (+15/-16)
4 files modified
lib/lp/services/config/schema-lazr.conf (+4/-0)
lib/lp/services/mail/tests/test_signedmessage.py (+7/-1)
lib/lp/services/tests/test_timeout.py (+1/-13)
lib/lp/services/timeout.py (+3/-2)
To merge this branch: bzr merge lp:~cjwatson/launchpad/global-urlfetch-timeout
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+364669@code.launchpad.net

Commit message

Give urlfetch a default timeout, fixing a regression in process-mail.

Description of the change

The default timeout assertion has been driving me nuts ever since I started converting more things to urlfetch, so let's make urlfetch have a reasonable default for scripts. Contexts with a timeout budget need to override this, of course, but they generally already do.

In theory this should obviate a number of more specific timeout configuration items, but I decided to leave those alone in case they need isolated overrides for some reason; we can just avoid adding more unless they're specifically needed.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/services/config/schema-lazr.conf'
--- lib/lp/services/config/schema-lazr.conf 2019-03-13 16:12:42 +0000
+++ lib/lp/services/config/schema-lazr.conf 2019-03-18 12:23:22 +0000
@@ -1104,6 +1104,10 @@
1104# datatype: string1104# datatype: string
1105feature_flags_endpoint:1105feature_flags_endpoint:
11061106
1107# Default timeout for fetching remote URLs. Overridden to something more
1108# specific in many contexts, but this provides a fallback.
1109urlfetch_timeout: 30
1110
1107[launchpad_session]1111[launchpad_session]
1108# The database connection string.1112# The database connection string.
1109# datatype: pgconnection1113# datatype: pgconnection
11101114
=== modified file 'lib/lp/services/mail/tests/test_signedmessage.py'
--- lib/lp/services/mail/tests/test_signedmessage.py 2018-04-22 23:30:37 +0000
+++ lib/lp/services/mail/tests/test_signedmessage.py 2019-03-18 12:23:22 +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"""Test the SignedMessage class."""4"""Test the SignedMessage class."""
@@ -32,6 +32,7 @@
32 import_public_test_keys,32 import_public_test_keys,
33 import_secret_test_key,33 import_secret_test_key,
34 )34 )
35from lp.testing.keyserver import KeyServerTac
35from lp.testing.layers import DatabaseFunctionalLayer36from lp.testing.layers import DatabaseFunctionalLayer
3637
3738
@@ -44,6 +45,9 @@
44 # Login with admin roles as we aren't testing access here.45 # Login with admin roles as we aren't testing access here.
45 TestCaseWithFactory.setUp(self, 'admin@canonical.com')46 TestCaseWithFactory.setUp(self, 'admin@canonical.com')
46 import_public_test_keys()47 import_public_test_keys()
48 # Ensure that tests will try to fetch keys from the keyserver.
49 self.useFixture(KeyServerTac())
50 getUtility(IGPGHandler).resetLocalState()
4751
48 def test_unsigned_message(self):52 def test_unsigned_message(self):
49 # An unsigned message will not have a signature nor signed content,53 # An unsigned message will not have a signature nor signed content,
@@ -73,6 +77,7 @@
73 msg = self.factory.makeSignedMessage(77 msg = self.factory.makeSignedMessage(
74 email_address=sender.preferredemail.email,78 email_address=sender.preferredemail.email,
75 body=body, signing_context=signing_context)79 body=body, signing_context=signing_context)
80 getUtility(IGPGHandler).resetLocalState()
76 self.assertFalse(msg.is_multipart())81 self.assertFalse(msg.is_multipart())
77 return signed_message_from_string(msg.as_string())82 return signed_message_from_string(msg.as_string())
7883
@@ -134,6 +139,7 @@
134 signature = gpghandler.signContent(139 signature = gpghandler.signContent(
135 canonicalise_line_endings(body_text.as_string()),140 canonicalise_line_endings(body_text.as_string()),
136 key, 'test', gpgme.SIG_MODE_DETACH)141 key, 'test', gpgme.SIG_MODE_DETACH)
142 gpghandler.resetLocalState()
137143
138 attachment = Message()144 attachment = Message()
139 attachment.set_payload(signature)145 attachment.set_payload(signature)
140146
=== modified file 'lib/lp/services/tests/test_timeout.py'
--- lib/lp/services/tests/test_timeout.py 2018-07-13 12:48:19 +0000
+++ lib/lp/services/tests/test_timeout.py 2019-03-18 12:23:22 +0000
@@ -1,4 +1,4 @@
1# Copyright 2012-2018 Canonical Ltd. This software is licensed under the1# Copyright 2012-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"""timeout.py tests.4"""timeout.py tests.
@@ -370,8 +370,6 @@
370 def test_urlfetch_no_proxy_by_default(self):370 def test_urlfetch_no_proxy_by_default(self):
371 """urlfetch does not use a proxy by default."""371 """urlfetch does not use a proxy by default."""
372 self.pushConfig('launchpad', http_proxy='http://proxy.example:3128/')372 self.pushConfig('launchpad', http_proxy='http://proxy.example:3128/')
373 set_default_timeout_function(lambda: 1)
374 self.addCleanup(set_default_timeout_function, None)
375 fake_send = FakeMethod(result=Response())373 fake_send = FakeMethod(result=Response())
376 self.useFixture(374 self.useFixture(
377 MonkeyPatch('requests.adapters.HTTPAdapter.send', fake_send))375 MonkeyPatch('requests.adapters.HTTPAdapter.send', fake_send))
@@ -382,8 +380,6 @@
382 """urlfetch uses proxies if explicitly requested."""380 """urlfetch uses proxies if explicitly requested."""
383 proxy = 'http://proxy.example:3128/'381 proxy = 'http://proxy.example:3128/'
384 self.pushConfig('launchpad', http_proxy=proxy)382 self.pushConfig('launchpad', http_proxy=proxy)
385 set_default_timeout_function(lambda: 1)
386 self.addCleanup(set_default_timeout_function, None)
387 fake_send = FakeMethod(result=Response())383 fake_send = FakeMethod(result=Response())
388 self.useFixture(384 self.useFixture(
389 MonkeyPatch('requests.adapters.HTTPAdapter.send', fake_send))385 MonkeyPatch('requests.adapters.HTTPAdapter.send', fake_send))
@@ -394,8 +390,6 @@
394390
395 def test_urlfetch_does_not_support_ftp_urls_by_default(self):391 def test_urlfetch_does_not_support_ftp_urls_by_default(self):
396 """urlfetch() does not support ftp urls by default."""392 """urlfetch() does not support ftp urls by default."""
397 set_default_timeout_function(lambda: 1)
398 self.addCleanup(set_default_timeout_function, None)
399 url = 'ftp://localhost/'393 url = 'ftp://localhost/'
400 e = self.assertRaises(InvalidSchema, urlfetch, url)394 e = self.assertRaises(InvalidSchema, urlfetch, url)
401 self.assertEqual(395 self.assertEqual(
@@ -420,8 +414,6 @@
420 self.pushConfig('launchpad', http_proxy=http_server_url)414 self.pushConfig('launchpad', http_proxy=http_server_url)
421 t = threading.Thread(target=success_result)415 t = threading.Thread(target=success_result)
422 t.start()416 t.start()
423 set_default_timeout_function(lambda: 1)
424 self.addCleanup(set_default_timeout_function, None)
425 response = urlfetch(417 response = urlfetch(
426 'ftp://example.com/', use_proxy=True, allow_ftp=True)418 'ftp://example.com/', use_proxy=True, allow_ftp=True)
427 self.assertThat(response, MatchesStructure(419 self.assertThat(response, MatchesStructure(
@@ -432,8 +424,6 @@
432424
433 def test_urlfetch_does_not_support_file_urls_by_default(self):425 def test_urlfetch_does_not_support_file_urls_by_default(self):
434 """urlfetch() does not support file urls by default."""426 """urlfetch() does not support file urls by default."""
435 set_default_timeout_function(lambda: 1)
436 self.addCleanup(set_default_timeout_function, None)
437 test_path = self.useFixture(TempDir()).join('file')427 test_path = self.useFixture(TempDir()).join('file')
438 write_file(test_path, '')428 write_file(test_path, '')
439 url = 'file://' + test_path429 url = 'file://' + test_path
@@ -443,8 +433,6 @@
443433
444 def test_urlfetch_supports_file_urls_if_allow_file(self):434 def test_urlfetch_supports_file_urls_if_allow_file(self):
445 """urlfetch() supports file urls if explicitly asked to do so."""435 """urlfetch() supports file urls if explicitly asked to do so."""
446 set_default_timeout_function(lambda: 1)
447 self.addCleanup(set_default_timeout_function, None)
448 test_path = self.useFixture(TempDir()).join('file')436 test_path = self.useFixture(TempDir()).join('file')
449 write_file(test_path, 'Success.')437 write_file(test_path, 'Success.')
450 url = 'file://' + test_path438 url = 'file://' + test_path
451439
=== modified file 'lib/lp/services/timeout.py'
--- lib/lp/services/timeout.py 2018-07-26 14:19:38 +0000
+++ lib/lp/services/timeout.py 2019-03-18 12:23:22 +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"""Helpers to time out external operations."""4"""Helpers to time out external operations."""
@@ -396,7 +396,8 @@
396396
397def urlfetch(url, **request_kwargs):397def urlfetch(url, **request_kwargs):
398 """Wrapper for `requests.get()` that times out."""398 """Wrapper for `requests.get()` that times out."""
399 return URLFetcher().fetch(url, **request_kwargs)399 with default_timeout(config.launchpad.urlfetch_timeout):
400 return URLFetcher().fetch(url, **request_kwargs)
400401
401402
402class TransportWithTimeout(Transport):403class TransportWithTimeout(Transport):
403404
=== added symlink 'lib/lp/testing/keyserver/tests/keys/0xDB25975602BA5EF6.get'
=== target is u'0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543.get'