Merge lp:~julian-edwards/maas/download-service-exceptions into lp:~maas-committers/maas/trunk

Proposed by Julian Edwards
Status: Merged
Approved by: Julian Edwards
Approved revision: no longer in the source branch.
Merged at revision: 2828
Proposed branch: lp:~julian-edwards/maas/download-service-exceptions
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 121 lines (+50/-6)
2 files modified
src/provisioningserver/pserv_services/image_download_service.py (+22/-5)
src/provisioningserver/pserv_services/tests/test_image_download_service.py (+28/-1)
To merge this branch: bzr merge lp:~julian-edwards/maas/download-service-exceptions
Reviewer Review Type Date Requested Status
Jeroen T. Vermeulen (community) Approve
Review via email: mp+232352@code.launchpad.net

Commit message

Ensure that exceptions are caught inside the PeriodicImageDownloadService, which would otherwise make it stop running.

Description of the change

.

To post a comment you must log in.
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

Nicely done. Just one note: shouldn't the existing tests then call try_download instead of maybe_start_download, so that the success case is covered?

review: Approve
Revision history for this message
Julian Edwards (julian-edwards) wrote :

On Wednesday 27 August 2014 07:15:51 you wrote:
> Review: Approve
>
> Nicely done. Just one note: shouldn't the existing tests then call
> try_download instead of maybe_start_download, so that the success case is
> covered?

It's already doing that; it relies on the service itself calling the functions
in the service object.

Thanks for the review!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/provisioningserver/pserv_services/image_download_service.py'
--- src/provisioningserver/pserv_services/image_download_service.py 2014-08-27 05:59:05 +0000
+++ src/provisioningserver/pserv_services/image_download_service.py 2014-08-27 07:10:34 +0000
@@ -27,13 +27,17 @@
27 GetBootSources,27 GetBootSources,
28 GetBootSourcesV2,28 GetBootSourcesV2,
29 )29 )
30from provisioningserver.utils.twisted import pause30from provisioningserver.utils.twisted import (
31 pause,
32 retries,
33 )
31from twisted.application.internet import TimerService34from twisted.application.internet import TimerService
32from twisted.internet.defer import (35from twisted.internet.defer import (
33 DeferredLock,36 DeferredLock,
34 inlineCallbacks,37 inlineCallbacks,
35 returnValue,38 returnValue,
36 )39 )
40from twisted.python import log
37from twisted.spread.pb import NoSuchMethod41from twisted.spread.pb import NoSuchMethod
3842
3943
@@ -54,11 +58,24 @@
54 def __init__(self, client_service, reactor, cluster_uuid):58 def __init__(self, client_service, reactor, cluster_uuid):
55 # Call self.check() every self.check_interval.59 # Call self.check() every self.check_interval.
56 super(PeriodicImageDownloadService, self).__init__(60 super(PeriodicImageDownloadService, self).__init__(
57 self.check_interval, self.maybe_start_download)61 self.check_interval, self.try_download)
58 self.clock = reactor62 self.clock = reactor
59 self.client_service = client_service63 self.client_service = client_service
60 self.uuid = cluster_uuid64 self.uuid = cluster_uuid
6165
66 def try_download(self):
67 """Wrap download attempts in something that catches Failures.
68
69 Log the full error to the Twisted log, and a concise error to
70 the maas log.
71 """
72 def download_failure(failure):
73 log.err(failure)
74 maaslog.error(
75 "Failed to download images: %s", failure.getErrorMessage())
76
77 return self.maybe_start_download().addErrback(download_failure)
78
62 @inlineCallbacks79 @inlineCallbacks
63 def _get_boot_sources(self, client):80 def _get_boot_sources(self, client):
64 """Gets the boot sources from the region."""81 """Gets the boot sources from the region."""
@@ -80,13 +97,13 @@
80 client = None97 client = None
81 # Retry a few times, since this service usually comes up before98 # Retry a few times, since this service usually comes up before
82 # the RPC service.99 # the RPC service.
83 for _ in range(3):100 for elapsed, remaining, wait in retries(15, 5, self.clock):
84 try:101 try:
85 client = self.client_service.getClient()102 client = self.client_service.getClient()
86 break103 break
87 except NoConnectionsAvailable:104 except NoConnectionsAvailable:
88 yield pause(5)105 yield pause(wait, self.clock)
89 if client is None:106 else:
90 maaslog.error(107 maaslog.error(
91 "Can't initiate image download, no RPC connection to region.")108 "Can't initiate image download, no RPC connection to region.")
92 return109 return
93110
=== modified file 'src/provisioningserver/pserv_services/tests/test_image_download_service.py'
--- src/provisioningserver/pserv_services/tests/test_image_download_service.py 2014-08-27 03:38:28 +0000
+++ src/provisioningserver/pserv_services/tests/test_image_download_service.py 2014-08-27 07:10:34 +0000
@@ -17,6 +17,7 @@
1717
18from datetime import timedelta18from datetime import timedelta
1919
20from fixtures import FakeLogger
20from maastesting.factory import factory21from maastesting.factory import factory
21from maastesting.matchers import (22from maastesting.matchers import (
22 get_mock_calls,23 get_mock_calls,
@@ -41,9 +42,13 @@
41 GetBootSources,42 GetBootSources,
42 GetBootSourcesV2,43 GetBootSourcesV2,
43 )44 )
45from provisioningserver.rpc.testing import TwistedLoggerFixture
44from provisioningserver.testing.testcase import PservTestCase46from provisioningserver.testing.testcase import PservTestCase
45from provisioningserver.utils.twisted import pause47from provisioningserver.utils.twisted import pause
46from testtools.deferredruntest import AsynchronousDeferredRunTest48from testtools.deferredruntest import (
49 AsynchronousDeferredRunTest,
50 extract_result,
51 )
47from twisted.application.internet import TimerService52from twisted.application.internet import TimerService
48from twisted.internet import defer53from twisted.internet import defer
49from twisted.internet.task import Clock54from twisted.internet.task import Clock
@@ -205,6 +210,28 @@
205 clock.advance(1)210 clock.advance(1)
206 self.assertFalse(service_lock.locked)211 self.assertFalse(service_lock.locked)
207212
213 def test_logs_other_errors(self):
214 service = PeriodicImageDownloadService(
215 sentinel.rpc, Clock(), sentinel.uuid)
216
217 maybe_start_download = self.patch(service, "maybe_start_download")
218 maybe_start_download.return_value = defer.fail(
219 ZeroDivisionError("Such a shame I can't divide by zero"))
220
221 with FakeLogger("maas") as maaslog, TwistedLoggerFixture():
222 d = service.try_download()
223
224 self.assertEqual(None, extract_result(d))
225 self.assertDocTestMatches(
226 "Failed to download images: "
227 "Such a shame I can't divide by zero",
228 maaslog.output)
229
230
231class TestGetBootSources(PservTestCase):
232
233 run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=5)
234
208 @defer.inlineCallbacks235 @defer.inlineCallbacks
209 def test__get_boot_sources_calls_get_boot_sources_v2_before_v1(self):236 def test__get_boot_sources_calls_get_boot_sources_v2_before_v1(self):
210 clock = Clock()237 clock = Clock()