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
1=== modified file 'src/provisioningserver/pserv_services/image_download_service.py'
2--- src/provisioningserver/pserv_services/image_download_service.py 2014-08-27 05:59:05 +0000
3+++ src/provisioningserver/pserv_services/image_download_service.py 2014-08-27 07:10:34 +0000
4@@ -27,13 +27,17 @@
5 GetBootSources,
6 GetBootSourcesV2,
7 )
8-from provisioningserver.utils.twisted import pause
9+from provisioningserver.utils.twisted import (
10+ pause,
11+ retries,
12+ )
13 from twisted.application.internet import TimerService
14 from twisted.internet.defer import (
15 DeferredLock,
16 inlineCallbacks,
17 returnValue,
18 )
19+from twisted.python import log
20 from twisted.spread.pb import NoSuchMethod
21
22
23@@ -54,11 +58,24 @@
24 def __init__(self, client_service, reactor, cluster_uuid):
25 # Call self.check() every self.check_interval.
26 super(PeriodicImageDownloadService, self).__init__(
27- self.check_interval, self.maybe_start_download)
28+ self.check_interval, self.try_download)
29 self.clock = reactor
30 self.client_service = client_service
31 self.uuid = cluster_uuid
32
33+ def try_download(self):
34+ """Wrap download attempts in something that catches Failures.
35+
36+ Log the full error to the Twisted log, and a concise error to
37+ the maas log.
38+ """
39+ def download_failure(failure):
40+ log.err(failure)
41+ maaslog.error(
42+ "Failed to download images: %s", failure.getErrorMessage())
43+
44+ return self.maybe_start_download().addErrback(download_failure)
45+
46 @inlineCallbacks
47 def _get_boot_sources(self, client):
48 """Gets the boot sources from the region."""
49@@ -80,13 +97,13 @@
50 client = None
51 # Retry a few times, since this service usually comes up before
52 # the RPC service.
53- for _ in range(3):
54+ for elapsed, remaining, wait in retries(15, 5, self.clock):
55 try:
56 client = self.client_service.getClient()
57 break
58 except NoConnectionsAvailable:
59- yield pause(5)
60- if client is None:
61+ yield pause(wait, self.clock)
62+ else:
63 maaslog.error(
64 "Can't initiate image download, no RPC connection to region.")
65 return
66
67=== modified file 'src/provisioningserver/pserv_services/tests/test_image_download_service.py'
68--- src/provisioningserver/pserv_services/tests/test_image_download_service.py 2014-08-27 03:38:28 +0000
69+++ src/provisioningserver/pserv_services/tests/test_image_download_service.py 2014-08-27 07:10:34 +0000
70@@ -17,6 +17,7 @@
71
72 from datetime import timedelta
73
74+from fixtures import FakeLogger
75 from maastesting.factory import factory
76 from maastesting.matchers import (
77 get_mock_calls,
78@@ -41,9 +42,13 @@
79 GetBootSources,
80 GetBootSourcesV2,
81 )
82+from provisioningserver.rpc.testing import TwistedLoggerFixture
83 from provisioningserver.testing.testcase import PservTestCase
84 from provisioningserver.utils.twisted import pause
85-from testtools.deferredruntest import AsynchronousDeferredRunTest
86+from testtools.deferredruntest import (
87+ AsynchronousDeferredRunTest,
88+ extract_result,
89+ )
90 from twisted.application.internet import TimerService
91 from twisted.internet import defer
92 from twisted.internet.task import Clock
93@@ -205,6 +210,28 @@
94 clock.advance(1)
95 self.assertFalse(service_lock.locked)
96
97+ def test_logs_other_errors(self):
98+ service = PeriodicImageDownloadService(
99+ sentinel.rpc, Clock(), sentinel.uuid)
100+
101+ maybe_start_download = self.patch(service, "maybe_start_download")
102+ maybe_start_download.return_value = defer.fail(
103+ ZeroDivisionError("Such a shame I can't divide by zero"))
104+
105+ with FakeLogger("maas") as maaslog, TwistedLoggerFixture():
106+ d = service.try_download()
107+
108+ self.assertEqual(None, extract_result(d))
109+ self.assertDocTestMatches(
110+ "Failed to download images: "
111+ "Such a shame I can't divide by zero",
112+ maaslog.output)
113+
114+
115+class TestGetBootSources(PservTestCase):
116+
117+ run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=5)
118+
119 @defer.inlineCallbacks
120 def test__get_boot_sources_calls_get_boot_sources_v2_before_v1(self):
121 clock = Clock()