Merge lp:~blake-rouse/maas/fix-1402109-1.7 into lp:maas/1.7

Proposed by Blake Rouse
Status: Merged
Merged at revision: 3333
Proposed branch: lp:~blake-rouse/maas/fix-1402109-1.7
Merge into: lp:maas/1.7
Diff against target: 313 lines (+143/-27)
2 files modified
src/provisioningserver/rpc/clusterservice.py (+25/-4)
src/provisioningserver/rpc/tests/test_clusterservice.py (+118/-23)
To merge this branch: bzr merge lp:~blake-rouse/maas/fix-1402109-1.7
Reviewer Review Type Date Requested Status
Christian Reis (community) Approve
Blake Rouse (community) Approve
Review via email: mp+245116@code.launchpad.net

Commit message

deferToThread all probe-and-enlist functions on the cluster.

To post a comment you must log in.
Revision history for this message
Blake Rouse (blake-rouse) wrote :

Self-approving backport.

review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (19.6 KiB)

The attempt to merge lp:~blake-rouse/maas/fix-1402109-1.7 into lp:maas/1.7 failed. Below is the output from the failed tests.

Ign http://security.ubuntu.com trusty-security InRelease
Get:1 http://security.ubuntu.com trusty-security Release.gpg [933 B]
Ign http://nova.clouds.archive.ubuntu.com trusty InRelease
Get:2 http://security.ubuntu.com trusty-security Release [62.0 kB]
Ign http://nova.clouds.archive.ubuntu.com trusty-updates InRelease
Hit http://nova.clouds.archive.ubuntu.com trusty Release.gpg
Get:3 http://nova.clouds.archive.ubuntu.com trusty-updates Release.gpg [933 B]
Hit http://nova.clouds.archive.ubuntu.com trusty Release
Get:4 http://nova.clouds.archive.ubuntu.com trusty-updates Release [62.0 kB]
Get:5 http://security.ubuntu.com trusty-security/main Sources [56.8 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty/main Sources
Get:6 http://security.ubuntu.com trusty-security/universe Sources [17.4 kB]
Get:7 http://security.ubuntu.com trusty-security/main amd64 Packages [181 kB]
Get:8 http://security.ubuntu.com trusty-security/universe amd64 Packages [76.0 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty/universe Sources
Hit http://nova.clouds.archive.ubuntu.com trusty/main amd64 Packages
Hit http://nova.clouds.archive.ubuntu.com trusty/universe amd64 Packages
Hit http://security.ubuntu.com trusty-security/main Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty/main Translation-en
Hit http://security.ubuntu.com trusty-security/universe Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty/universe Translation-en
Get:9 http://nova.clouds.archive.ubuntu.com trusty-updates/main Sources [148 kB]
Get:10 http://nova.clouds.archive.ubuntu.com trusty-updates/universe Sources [95.6 kB]
Get:11 http://nova.clouds.archive.ubuntu.com trusty-updates/main amd64 Packages [385 kB]
Get:12 http://nova.clouds.archive.ubuntu.com trusty-updates/universe amd64 Packages [229 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty-updates/main Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty-updates/universe Translation-en
Ign http://nova.clouds.archive.ubuntu.com trusty/main Translation-en_US
Ign http://nova.clouds.archive.ubuntu.com trusty/universe Translation-en_US
Fetched 1,315 kB in 2s (448 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
     --no-install-recommends install apache2 authbind bind9 bind9utils build-essential bzr-builddeb curl daemontools debhelper dh-apport distro-info dnsutils firefox freeipmi-tools gjs ipython isc-dhcp-common libjs-raphael libjs-yui3-full libjs-yui3-min libpq-dev make pep8 postgresql pyflakes python-amqplib python-bzrlib python-celery python-convoy python-crochet python-cssselect python-curtin python-dev python-distro-info python-django python-django-piston python-django-south python-djorm-ext-pgarray python-docutils python-extras python-fixtures python-flake8 python-formencode python-hivex python-httplib2 python-jinja2 python-jsonschema python-lockfile python-lxml python-mimeparse python-mock python-netaddr python-netifaces python-nose python-oauth python-oops python-oops-amqp python-oops-datedir-repo python-oops-twisted python-oops-wsgi python...

Revision history for this message
Christian Reis (kiko) wrote :

Thanks Blake!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/provisioningserver/rpc/clusterservice.py'
2--- src/provisioningserver/rpc/clusterservice.py 2014-12-08 16:50:57 +0000
3+++ src/provisioningserver/rpc/clusterservice.py 2014-12-18 15:28:52 +0000
4@@ -16,6 +16,7 @@
5 "ClusterClientService",
6 ]
7
8+from functools import partial
9 import json
10 import logging
11 from os import urandom
12@@ -108,6 +109,14 @@
13 maaslog = get_maas_logger("rpc.cluster")
14
15
16+def catch_probe_and_enlist_error(name, failure):
17+ """Logs any errors when trying to probe and enlist a chassis."""
18+ maaslog.error(
19+ "Failed to probe and enlist %s nodes: %s",
20+ name, failure.getErrorMessage())
21+ return None
22+
23+
24 class Cluster(RPCProtocol):
25 """The RPC protocol supported by a cluster controller.
26
27@@ -349,7 +358,10 @@
28
29 Implementation of :py:class:`~provisioningserver.rpc.cluster.AddVirsh`.
30 """
31- probe_virsh_and_enlist(poweraddr, password, prefix_filter)
32+ d = deferToThread(
33+ probe_virsh_and_enlist,
34+ poweraddr, password, prefix_filter)
35+ d.addErrback(partial(catch_probe_and_enlist_error, "virsh"))
36 return {}
37
38 @cluster.AddSeaMicro15k.responder
39@@ -361,9 +373,12 @@
40 """
41 ip = find_ip_via_arp(mac)
42 if ip is not None:
43- probe_seamicro15k_and_enlist(
44+ d = deferToThread(
45+ probe_seamicro15k_and_enlist,
46 ip, username, password,
47 power_control=power_control)
48+ d.addErrback(
49+ partial(catch_probe_and_enlist_error, "SeaMicro 15000"))
50 else:
51 message = "Couldn't find IP address for MAC %s" % mac
52 maaslog.warning(message)
53@@ -377,7 +392,10 @@
54 Implemention of
55 :py:class:`~provisioningserver.rpc.cluster.EnlistNodesFromMSCM`.
56 """
57- probe_and_enlist_mscm(host, username, password)
58+ d = deferToThread(
59+ probe_and_enlist_mscm,
60+ host, username, password)
61+ d.addErrback(partial(catch_probe_and_enlist_error, "Moonshot"))
62 return {}
63
64 @cluster.EnlistNodesFromUCSM.responder
65@@ -387,7 +405,10 @@
66 Implemention of
67 :py:class:`~provisioningserver.rpc.cluster.EnlistNodesFromUCSM`.
68 """
69- probe_and_enlist_ucsm(url, username, password)
70+ d = deferToThread(
71+ probe_and_enlist_ucsm,
72+ url, username, password)
73+ d.addErrback(partial(catch_probe_and_enlist_error, "UCS"))
74 return {}
75
76
77
78=== modified file 'src/provisioningserver/rpc/tests/test_clusterservice.py'
79--- src/provisioningserver/rpc/tests/test_clusterservice.py 2014-12-16 19:29:45 +0000
80+++ src/provisioningserver/rpc/tests/test_clusterservice.py 2014-12-18 15:28:52 +0000
81@@ -32,6 +32,7 @@
82 from maastesting.factory import factory
83 from maastesting.matchers import (
84 IsUnfiredDeferred,
85+ MockAnyCall,
86 MockCalledOnceWith,
87 MockCalledWith,
88 MockCallsMatch,
89@@ -1886,9 +1887,9 @@
90 cluster.AddVirsh.commandName)
91 self.assertIsNotNone(responder)
92
93- def test__calls_probe_virsh_and_enlist(self):
94- probe_virsh_and_enlist = self.patch_autospec(
95- clusterservice, 'probe_virsh_and_enlist')
96+ def test__calls_deferToThread_with_probe_virsh_and_enlist(self):
97+ mock_deferToThread = self.patch_autospec(
98+ clusterservice, 'deferToThread')
99 poweraddr = factory.make_name('poweraddr')
100 password = factory.make_name('password')
101 prefix_filter = factory.make_name('prefix_filter')
102@@ -1898,32 +1899,55 @@
103 "prefix_filter": prefix_filter,
104 })
105 self.assertThat(
106- probe_virsh_and_enlist, MockCalledOnceWith(
107+ mock_deferToThread, MockCalledOnceWith(
108+ clusterservice.probe_virsh_and_enlist,
109 poweraddr, password, prefix_filter))
110
111 def test__password_is_optional(self):
112- probe_virsh_and_enlist = self.patch_autospec(
113- clusterservice, 'probe_virsh_and_enlist')
114+ mock_deferToThread = self.patch_autospec(
115+ clusterservice, 'deferToThread')
116 poweraddr = factory.make_name('poweraddr')
117 call_responder(Cluster(), cluster.AddVirsh, {
118 "poweraddr": poweraddr,
119 "password": None,
120 })
121 self.assertThat(
122- probe_virsh_and_enlist, MockCalledOnceWith(
123+ mock_deferToThread, MockCalledOnceWith(
124+ clusterservice.probe_virsh_and_enlist,
125 poweraddr, None, None))
126
127 def test__can_be_called_without_password_key(self):
128- probe_virsh_and_enlist = self.patch_autospec(
129- clusterservice, 'probe_virsh_and_enlist')
130+ mock_deferToThread = self.patch_autospec(
131+ clusterservice, 'deferToThread')
132 poweraddr = factory.make_name('poweraddr')
133 call_responder(Cluster(), cluster.AddVirsh, {
134 "poweraddr": poweraddr,
135 })
136 self.assertThat(
137- probe_virsh_and_enlist, MockCalledOnceWith(
138+ mock_deferToThread, MockCalledOnceWith(
139+ clusterservice.probe_virsh_and_enlist,
140 poweraddr, None, None))
141
142+ def test__logs_error_to_maaslog(self):
143+ fake_error = factory.make_name('error')
144+ self.patch(clusterservice, 'maaslog')
145+ mock_deferToThread = self.patch_autospec(
146+ clusterservice, 'deferToThread')
147+ mock_deferToThread.return_value = fail(Exception(fake_error))
148+ poweraddr = factory.make_name('poweraddr')
149+ password = factory.make_name('password')
150+ prefix_filter = factory.make_name('prefix_filter')
151+ call_responder(Cluster(), cluster.AddVirsh, {
152+ "poweraddr": poweraddr,
153+ "password": password,
154+ "prefix_filter": prefix_filter,
155+ })
156+ self.assertThat(
157+ clusterservice.maaslog.error,
158+ MockAnyCall(
159+ "Failed to probe and enlist %s nodes: %s",
160+ "virsh", fake_error))
161+
162
163 class TestClusterProtocol_AddSeaMicro15k(MAASTestCase):
164
165@@ -1936,7 +1960,7 @@
166 def test__calls_find_ip_via_arp(self):
167 # Prevent any actual probing from happing.
168 self.patch_autospec(
169- clusterservice, 'probe_seamicro15k_and_enlist')
170+ clusterservice, 'deferToThread')
171 find_ip_via_arp = self.patch_autospec(
172 clusterservice, 'find_ip_via_arp')
173 find_ip_via_arp.return_value = factory.make_ipv4_address()
174@@ -1980,9 +2004,9 @@
175 MockCalledOnceWith(
176 "Couldn't find IP address for MAC %s" % mac))
177
178- def test__calls_probe_seamicro15k_and_enlist(self):
179- probe_seamicro15k_and_enlist = self.patch_autospec(
180- clusterservice, 'probe_seamicro15k_and_enlist')
181+ def test__calls_deferToThread_with_probe_seamicro15k_and_enlist(self):
182+ mock_deferToThread = self.patch_autospec(
183+ clusterservice, 'deferToThread')
184 find_ip_via_arp = self.patch_autospec(
185 clusterservice, 'find_ip_via_arp')
186 find_ip_via_arp.return_value = factory.make_ipv4_address()
187@@ -1999,10 +2023,37 @@
188 })
189
190 self.assertThat(
191- probe_seamicro15k_and_enlist, MockCalledOnceWith(
192+ mock_deferToThread, MockCalledOnceWith(
193+ clusterservice.probe_seamicro15k_and_enlist,
194 find_ip_via_arp.return_value, username, password,
195 power_control=power_control))
196
197+ def test__logs_error_to_maaslog(self):
198+ fake_error = factory.make_name('error')
199+ self.patch(clusterservice, 'maaslog')
200+ mock_deferToThread = self.patch_autospec(
201+ clusterservice, 'deferToThread')
202+ mock_deferToThread.return_value = fail(Exception(fake_error))
203+ find_ip_via_arp = self.patch_autospec(
204+ clusterservice, 'find_ip_via_arp')
205+ find_ip_via_arp.return_value = factory.make_ipv4_address()
206+
207+ mac = factory.make_mac_address()
208+ username = factory.make_name('user')
209+ password = factory.make_name('password')
210+ power_control = factory.make_name('power_control')
211+ call_responder(Cluster(), cluster.AddSeaMicro15k, {
212+ "mac": mac,
213+ "username": username,
214+ "password": password,
215+ "power_control": power_control,
216+ })
217+ self.assertThat(
218+ clusterservice.maaslog.error,
219+ MockAnyCall(
220+ "Failed to probe and enlist %s nodes: %s",
221+ "SeaMicro 15000", fake_error))
222+
223
224 class TestClusterProtocol_EnlistNodesFromMSCM(MAASTestCase):
225
226@@ -2012,9 +2063,9 @@
227 cluster.EnlistNodesFromMSCM.commandName)
228 self.assertIsNotNone(responder)
229
230- def test__calls_probe_and_enlist_mscm(self):
231- probe_and_enlist_mscm = self.patch_autospec(
232- clusterservice, 'probe_and_enlist_mscm')
233+ def test__deferToThread_with_probe_and_enlist_mscm(self):
234+ mock_deferToThread = self.patch_autospec(
235+ clusterservice, 'deferToThread')
236
237 host = factory.make_name('host')
238 username = factory.make_name('user')
239@@ -2027,9 +2078,31 @@
240 })
241
242 self.assertThat(
243- probe_and_enlist_mscm, MockCalledOnceWith(
244+ mock_deferToThread, MockCalledOnceWith(
245+ clusterservice.probe_and_enlist_mscm,
246 host, username, password))
247
248+ def test__logs_error_to_maaslog(self):
249+ fake_error = factory.make_name('error')
250+ self.patch(clusterservice, 'maaslog')
251+ mock_deferToThread = self.patch_autospec(
252+ clusterservice, 'deferToThread')
253+ mock_deferToThread.return_value = fail(Exception(fake_error))
254+ host = factory.make_name('host')
255+ username = factory.make_name('user')
256+ password = factory.make_name('password')
257+
258+ call_responder(Cluster(), cluster.EnlistNodesFromMSCM, {
259+ "host": host,
260+ "username": username,
261+ "password": password,
262+ })
263+ self.assertThat(
264+ clusterservice.maaslog.error,
265+ MockAnyCall(
266+ "Failed to probe and enlist %s nodes: %s",
267+ "Moonshot", fake_error))
268+
269
270 class TestClusterProtocol_EnlistNodesFromUCSM(MAASTestCase):
271
272@@ -2039,9 +2112,9 @@
273 cluster.EnlistNodesFromUCSM.commandName)
274 self.assertIsNotNone(responder)
275
276- def test__calls_probe_and_enlist_ucsm(self):
277- probe_and_enlist_ucsm = self.patch_autospec(
278- clusterservice, 'probe_and_enlist_ucsm')
279+ def test__calls_deferToThread_with_probe_and_enlist_ucsm(self):
280+ mock_deferToThread = self.patch_autospec(
281+ clusterservice, 'deferToThread')
282
283 url = factory.make_url()
284 username = factory.make_name('user')
285@@ -2054,5 +2127,27 @@
286 })
287
288 self.assertThat(
289- probe_and_enlist_ucsm, MockCalledOnceWith(
290+ mock_deferToThread, MockCalledOnceWith(
291+ clusterservice.probe_and_enlist_ucsm,
292 url, username, password))
293+
294+ def test__logs_error_to_maaslog(self):
295+ fake_error = factory.make_name('error')
296+ self.patch(clusterservice, 'maaslog')
297+ mock_deferToThread = self.patch_autospec(
298+ clusterservice, 'deferToThread')
299+ mock_deferToThread.return_value = fail(Exception(fake_error))
300+ url = factory.make_url()
301+ username = factory.make_name('user')
302+ password = factory.make_name('password')
303+
304+ call_responder(Cluster(), cluster.EnlistNodesFromUCSM, {
305+ "url": url,
306+ "username": username,
307+ "password": password,
308+ })
309+ self.assertThat(
310+ clusterservice.maaslog.error,
311+ MockAnyCall(
312+ "Failed to probe and enlist %s nodes: %s",
313+ "UCS", fake_error))

Subscribers

People subscribed via source and target branches

to all changes: