Merge lp:~lamont/maas/bug-1562106 into lp:~maas-committers/maas/trunk

Proposed by LaMont Jones
Status: Merged
Approved by: LaMont Jones
Approved revision: no longer in the source branch.
Merged at revision: 4849
Proposed branch: lp:~lamont/maas/bug-1562106
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 366 lines (+270/-14)
3 files modified
src/maasserver/triggers/tests/helper.py (+48/-0)
src/maasserver/triggers/tests/test_websocket_listener.py (+209/-0)
src/maasserver/triggers/websocket.py (+13/-14)
To merge this branch: bzr merge lp:~lamont/maas/bug-1562106
Reviewer Review Type Date Requested Status
Blake Rouse (community) Approve
Andres Rodriguez (community) Approve
Review via email: mp+290241@code.launchpad.net

Commit message

Typo in the trigger for staticip address updates and insert/deletes.

Description of the change

Typo in the trigger for staticip address updates and insert/deletes.

To post a comment you must log in.
Revision history for this message
Andres Rodriguez (andreserl) wrote :

lgtm! What about tests ? aren't there tests for this?

review: Approve
Revision history for this message
Blake Rouse (blake-rouse) wrote :

Tests?

review: Needs Fixing
Revision history for this message
Blake Rouse (blake-rouse) wrote :

Wow that was a lot of missing tests. Looks good now. Thanks for adding all the tests.

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

The attempt to merge lp:~lamont/maas/bug-1562106 into lp:maas failed. Below is the output from the failed tests.

Get:1 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial InRelease [116 kB]
Hit:2 http://security.ubuntu.com/ubuntu xenial-security InRelease
Hit:3 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates InRelease
Hit:4 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-backports InRelease
Get:5 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial/main Sources [1,107 kB]
Get:6 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial/universe Sources [7,517 kB]
Get:7 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial/main amd64 Packages [1,435 kB]
Get:8 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial/main Translation-en [731 kB]
Get:9 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial/universe amd64 Packages [7,249 kB]
Get:10 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial/universe Translation-en [4,188 kB]
Fetched 22.3 MB in 3s (6,214 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
    --no-install-recommends install apache2 archdetect-deb authbind bind9 bind9utils build-essential bzr-builddeb chromium-browser chromium-chromedriver curl daemontools debhelper dh-apport dh-systemd distro-info dnsutils firefox freeipmi-tools git gjs ipython isc-dhcp-common libjs-angularjs libjs-jquery libjs-jquery-hotkeys libjs-yui3-full libjs-yui3-min libpq-dev make nodejs-legacy npm postgresql pxelinux python3-all python3-apt python3-bson python3-convoy python3-coverage python3-crochet python3-cssselect python3-curtin python3-dev python3-distro-info python3-django python3-django-nose python3-django-piston3 python3-dnspython python3-docutils python3-formencode python3-hivex python3-httplib2 python3-jinja2 python3-jsonschema python3-lxml python3-mock python3-netaddr python3-netifaces python3-oauth python3-oauthlib python3-openssl python3-paramiko python3-petname python3-pexpect python3-psycopg2 python3-pyinotify python3-pyparsing python3-pyvmomi python3-requests python3-seamicroclient python3-setuptools python3-simplestreams python3-sphinx python3-tempita python3-twisted python3-txtftp python3-tz python3-yaml python3-zope.interface python-bson python-crochet python-django python-django-piston python-djorm-ext-pgarray python-formencode python-lxml python-netaddr python-netifaces python-pocket-lint python-psycopg2 python-tempita python-twisted python-yaml socat syslinux-common tgt ubuntu-cloudimage-keyring wget xvfb
Reading package lists...
Building dependency tree...
Reading state information...
apache2 is already the newest version (2.4.18-1ubuntu1).
archdetect-deb is already the newest version (1.114ubuntu4).
authbind is already the newest version (2.1.1+nmu1).
bind9 is already the newest version (1:9.10.3.dfsg.P4-5).
bind9utils is already the newest version (1:9.10.3.dfsg.P4-5).
build-essential is already the newest version (12.1ubuntu2).
curl is already the newest version (7.47.0-1ubuntu2).
debhelper is already the newest version (9.20160115ubuntu2).
dh-apport is already the newest version (2.20-0ubu...

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

The attempt to merge lp:~lamont/maas/bug-1562106 into lp:maas failed. Below is the output from the failed tests.

Hit:1 http://security.ubuntu.com/ubuntu xenial-security InRelease
Get:2 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial InRelease [116 kB]
Hit:3 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates InRelease
Hit:4 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-backports InRelease
Get:5 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial/universe Sources [7,517 kB]
Get:6 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial/universe amd64 Packages [7,249 kB]
Fetched 14.9 MB in 2s (4,983 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
    --no-install-recommends install apache2 archdetect-deb authbind bind9 bind9utils build-essential bzr-builddeb chromium-browser chromium-chromedriver curl daemontools debhelper dh-apport dh-systemd distro-info dnsutils firefox freeipmi-tools git gjs ipython isc-dhcp-common libjs-angularjs libjs-jquery libjs-jquery-hotkeys libjs-yui3-full libjs-yui3-min libpq-dev make nodejs-legacy npm postgresql pxelinux python3-all python3-apt python3-bson python3-convoy python3-coverage python3-crochet python3-cssselect python3-curtin python3-dev python3-distro-info python3-django python3-django-nose python3-django-piston3 python3-dnspython python3-docutils python3-formencode python3-hivex python3-httplib2 python3-jinja2 python3-jsonschema python3-lxml python3-mock python3-netaddr python3-netifaces python3-oauth python3-oauthlib python3-openssl python3-paramiko python3-petname python3-pexpect python3-psycopg2 python3-pyinotify python3-pyparsing python3-pyvmomi python3-requests python3-seamicroclient python3-setuptools python3-simplestreams python3-sphinx python3-tempita python3-twisted python3-txtftp python3-tz python3-yaml python3-zope.interface python-bson python-crochet python-django python-django-piston python-djorm-ext-pgarray python-formencode python-lxml python-netaddr python-netifaces python-pocket-lint python-psycopg2 python-tempita python-twisted python-yaml socat syslinux-common tgt ubuntu-cloudimage-keyring wget xvfb
Reading package lists...
Building dependency tree...
Reading state information...
apache2 is already the newest version (2.4.18-1ubuntu1).
archdetect-deb is already the newest version (1.114ubuntu4).
authbind is already the newest version (2.1.1+nmu1).
bind9 is already the newest version (1:9.10.3.dfsg.P4-5).
bind9utils is already the newest version (1:9.10.3.dfsg.P4-5).
build-essential is already the newest version (12.1ubuntu2).
curl is already the newest version (7.47.0-1ubuntu2).
debhelper is already the newest version (9.20160115ubuntu2).
dh-apport is already the newest version (2.20-0ubuntu3).
dh-systemd is already the newest version (1.29ubuntu1).
distro-info is already the newest version (0.14build1).
dnsutils is already the newest version (1:9.10.3.dfsg.P4-5).
firefox is already the newest version (45.0.1+build1-0ubuntu1).
freeipmi-tools is already the newest version (1.4.11-1ubuntu1).
git is already the newest version (1:2.7.4-0ubuntu1).
isc-dhcp-common is already the newest ...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/triggers/tests/helper.py'
2--- src/maasserver/triggers/tests/helper.py 2016-03-25 14:52:23 +0000
3+++ src/maasserver/triggers/tests/helper.py 2016-03-29 17:03:39 +0000
4@@ -16,6 +16,9 @@
5 from maasserver.models.blockdevice import BlockDevice
6 from maasserver.models.cacheset import CacheSet
7 from maasserver.models.dhcpsnippet import DHCPSnippet
8+from maasserver.models.dnsdata import DNSData
9+from maasserver.models.dnsresource import DNSResource
10+from maasserver.models.domain import Domain
11 from maasserver.models.event import Event
12 from maasserver.models.fabric import Fabric
13 from maasserver.models.filesystem import Filesystem
14@@ -134,6 +137,51 @@
15 return node.get_boot_interface()
16
17 @transactional
18+ def create_domain(self, params=None):
19+ if params is None:
20+ params = {}
21+ return factory.make_Domain(**params)
22+
23+ @transactional
24+ def update_domain(self, id, params):
25+ return apply_update_to_model(Domain, id, params)
26+
27+ @transactional
28+ def delete_domain(self, id):
29+ domain = Domain.objects.get(id=id)
30+ domain.delete()
31+
32+ @transactional
33+ def create_dnsresource(self, params=None):
34+ if params is None:
35+ params = {}
36+ return factory.make_DNSResource(**params)
37+
38+ @transactional
39+ def update_dnsresource(self, id, params):
40+ return apply_update_to_model(DNSResource, id, params)
41+
42+ @transactional
43+ def delete_dnsresource(self, id):
44+ dnsresource = DNSResource.objects.get(id=id)
45+ dnsresource.delete()
46+
47+ @transactional
48+ def create_dnsdata(self, params=None):
49+ if params is None:
50+ params = {}
51+ return factory.make_DNSData(**params)
52+
53+ @transactional
54+ def update_dnsdata(self, id, params):
55+ return apply_update_to_model(DNSData, id, params)
56+
57+ @transactional
58+ def delete_dnsdata(self, id):
59+ dnsdata = DNSData.objects.get(id=id)
60+ dnsdata.delete()
61+
62+ @transactional
63 def create_fabric(self, params=None):
64 if params is None:
65 params = {}
66
67=== modified file 'src/maasserver/triggers/tests/test_websocket_listener.py'
68--- src/maasserver/triggers/tests/test_websocket_listener.py 2016-03-25 14:52:23 +0000
69+++ src/maasserver/triggers/tests/test_websocket_listener.py 2016-03-29 17:03:39 +0000
70@@ -1281,6 +1281,215 @@
71 yield listener.stopService()
72
73
74+class TestDomainListener(
75+ MAASTransactionServerTestCase, TransactionalHelpersMixin):
76+ """End-to-end test of both the listeners code and the cluster
77+ triggers code."""
78+
79+ @wait_for_reactor
80+ @inlineCallbacks
81+ def test__calls_handler_on_create_notification(self):
82+ yield deferToDatabase(register_websocket_triggers)
83+ listener = self.make_listener_without_delay()
84+ dv = DeferredValue()
85+ listener.register("domain", lambda *args: dv.set(args))
86+ yield listener.startService()
87+ try:
88+ domain = yield deferToDatabase(self.create_domain)
89+ yield dv.get(timeout=2)
90+ self.assertEqual(('create', '%s' % domain.id), dv.value)
91+ finally:
92+ yield listener.stopService()
93+
94+ @wait_for_reactor
95+ @inlineCallbacks
96+ def test__calls_handler_on_update_notification(self):
97+ yield deferToDatabase(register_websocket_triggers)
98+ listener = self.make_listener_without_delay()
99+ dv = DeferredValue()
100+ listener.register("domain", lambda *args: dv.set(args))
101+ domain = yield deferToDatabase(self.create_domain)
102+
103+ yield listener.startService()
104+ try:
105+ yield deferToDatabase(
106+ self.update_domain,
107+ domain.id,
108+ {'name': factory.make_name('name')})
109+ yield dv.get(timeout=2)
110+ self.assertEqual(('update', '%s' % domain.id), dv.value)
111+ finally:
112+ yield listener.stopService()
113+
114+ @wait_for_reactor
115+ @inlineCallbacks
116+ def test__calls_handler_on_delete_notification(self):
117+ yield deferToDatabase(register_websocket_triggers)
118+ listener = self.make_listener_without_delay()
119+ dv = DeferredValue()
120+ listener.register("domain", lambda *args: dv.set(args))
121+ domain = yield deferToDatabase(self.create_domain)
122+ yield listener.startService()
123+ try:
124+ yield deferToDatabase(self.delete_domain, domain.id)
125+ yield dv.get(timeout=2)
126+ self.assertEqual(('delete', '%s' % domain.id), dv.value)
127+ finally:
128+ yield listener.stopService()
129+
130+ @wait_for_reactor
131+ @inlineCallbacks
132+ def test__calls_handler_with_update_on_ip_address_update(self):
133+ domain = yield deferToDatabase(self.create_domain)
134+ yield deferToDatabase(register_websocket_triggers)
135+ params = {
136+ 'node_type': NODE_TYPE.MACHINE,
137+ 'domain': domain,
138+ }
139+ node = yield deferToDatabase(self.create_node, params)
140+ interface = yield deferToDatabase(
141+ self.create_interface, {
142+ "node": node})
143+ subnet = yield deferToDatabase(self.create_subnet)
144+ ipaddress = yield deferToDatabase(
145+ self.create_staticipaddress, {
146+ "alloc_type": IPADDRESS_TYPE.AUTO,
147+ "interface": interface,
148+ "subnet": subnet,
149+ "ip": "",
150+ })
151+
152+ selected_ip = factory.pick_ip_in_network(subnet.get_ipnetwork())
153+ listener = PostgresListenerService()
154+ dv = DeferredValue()
155+ listener.register("domain", lambda *args: dv.set(args))
156+ yield listener.startService()
157+ try:
158+ yield deferToDatabase(
159+ self.update_staticipaddress, ipaddress.id, {
160+ "alloc_type": IPADDRESS_TYPE.STICKY,
161+ "ip": selected_ip})
162+ yield dv.get(timeout=2)
163+ self.assertEqual(('update', '%s' % domain.id), dv.value)
164+ finally:
165+ yield listener.stopService()
166+
167+ @wait_for_reactor
168+ @inlineCallbacks
169+ def test__calls_handler_on_dnsresource_create_notification(self):
170+ domain = yield deferToDatabase(self.create_domain)
171+ yield deferToDatabase(register_websocket_triggers)
172+ listener = self.make_listener_without_delay()
173+ dv = DeferredValue()
174+ listener.register("domain", lambda *args: dv.set(args))
175+ yield listener.startService()
176+ try:
177+ yield deferToDatabase(
178+ self.create_dnsresource, {"domain": domain})
179+ yield dv.get(timeout=2)
180+ self.assertEqual(('update', '%s' % domain.id), dv.value)
181+ finally:
182+ yield listener.stopService()
183+
184+ @wait_for_reactor
185+ @inlineCallbacks
186+ def test__calls_handler_on_dnsresource_update_notification(self):
187+ domain = yield deferToDatabase(self.create_domain)
188+ yield deferToDatabase(register_websocket_triggers)
189+ listener = self.make_listener_without_delay()
190+ dv = DeferredValue()
191+ dnsrr = yield deferToDatabase(
192+ self.create_dnsresource, {"domain": domain})
193+ listener.register("domain", lambda *args: dv.set(args))
194+
195+ yield listener.startService()
196+ try:
197+ yield deferToDatabase(
198+ self.update_dnsresource,
199+ dnsrr.id,
200+ {'name': factory.make_name('name')})
201+ yield dv.get(timeout=2)
202+ self.assertEqual(('update', '%s' % domain.id), dv.value)
203+ finally:
204+ yield listener.stopService()
205+
206+ #@wait_for_reactor
207+ @wait_for(360000)
208+ @inlineCallbacks
209+ def test__calls_handler_on_dnsresource_delete_notification(self):
210+ domain = yield deferToDatabase(self.create_domain)
211+ yield deferToDatabase(register_websocket_triggers)
212+ dnsrr = yield deferToDatabase(self.create_dnsresource, {
213+ 'domain': domain})
214+ listener = self.make_listener_without_delay()
215+ dv = DeferredValue()
216+ listener.register("domain", lambda *args: dv.set(args))
217+ yield listener.startService()
218+ try:
219+ yield deferToDatabase(self.delete_dnsresource, dnsrr.id)
220+ yield dv.get(timeout=2)
221+ self.assertEqual(('update', '%s' % domain.id), dv.value)
222+ finally:
223+ yield listener.stopService()
224+
225+ @wait_for_reactor
226+ @inlineCallbacks
227+ def test__calls_handler_on_dnsdata_create_notification(self):
228+ domain = yield deferToDatabase(self.create_domain)
229+ yield deferToDatabase(register_websocket_triggers)
230+ listener = self.make_listener_without_delay()
231+ dv = DeferredValue()
232+ listener.register("domain", lambda *args: dv.set(args))
233+ yield listener.startService()
234+ try:
235+ yield deferToDatabase(
236+ self.create_dnsdata, {"domain": domain})
237+ yield dv.get(timeout=2)
238+ self.assertEqual(('update', '%s' % domain.id), dv.value)
239+ finally:
240+ yield listener.stopService()
241+
242+ @wait_for_reactor
243+ @inlineCallbacks
244+ def test__calls_handler_on_dnsdata_update_notification(self):
245+ domain = yield deferToDatabase(self.create_domain)
246+ yield deferToDatabase(register_websocket_triggers)
247+ listener = self.make_listener_without_delay()
248+ dv = DeferredValue()
249+ dnsdata = yield deferToDatabase(
250+ self.create_dnsdata, {"domain": domain})
251+ listener.register("domain", lambda *args: dv.set(args))
252+
253+ yield listener.startService()
254+ try:
255+ yield deferToDatabase(
256+ self.update_dnsdata,
257+ dnsdata.id, {
258+ 'ttl': random.randint(100, 199)})
259+ yield dv.get(timeout=2)
260+ self.assertEqual(('update', '%s' % domain.id), dv.value)
261+ finally:
262+ yield listener.stopService()
263+
264+ @wait_for_reactor
265+ @inlineCallbacks
266+ def test__calls_handler_on_dnsdata_delete_notification(self):
267+ domain = yield deferToDatabase(self.create_domain)
268+ yield deferToDatabase(register_websocket_triggers)
269+ listener = self.make_listener_without_delay()
270+ dv = DeferredValue()
271+ listener.register("domain", lambda *args: dv.set(args))
272+ dnsdata = yield deferToDatabase(self.create_dnsdata, {
273+ "domain": domain})
274+ yield listener.startService()
275+ try:
276+ yield deferToDatabase(self.delete_dnsdata, dnsdata.id)
277+ yield dv.get(timeout=2)
278+ self.assertEqual(('update', '%s' % domain.id), dv.value)
279+ finally:
280+ yield listener.stopService()
281+
282+
283 class TestSubnetListener(
284 MAASTransactionServerTestCase, TransactionalHelpersMixin):
285 """End-to-end test of both the listeners code and the cluster
286
287=== modified file 'src/maasserver/triggers/websocket.py'
288--- src/maasserver/triggers/websocket.py 2016-03-25 14:52:23 +0000
289+++ src/maasserver/triggers/websocket.py 2016-03-29 17:03:39 +0000
290@@ -600,7 +600,9 @@
291 DECLARE
292 dom RECORD;
293 BEGIN
294- IF OLD.ip != NEW.ip THEN
295+ IF ((OLD.ip IS NULL and NEW.ip IS NOT NULL) OR
296+ (OLD.ip IS NOT NULL and NEW.ip IS NULL) OR
297+ OLD.ip != NEW.ip) THEN
298 FOR dom IN (
299 SELECT DISTINCT ON (domain.id)
300 domain.id
301@@ -610,7 +612,7 @@
302 JOIN maasserver_interface AS interface ON
303 iia.interface_id = interface.id
304 JOIN maasserver_node AS node ON
305- node.boot_interface_id = interface.id) ON
306+ node.id = interface.node_id) ON
307 iia.staticipaddress_id = staticipaddress.id
308 LEFT JOIN (
309 maasserver_dnsresource_ip_addresses AS dia
310@@ -621,7 +623,7 @@
311 domain.id = node.domain_id OR domain.id = dnsresource.domain_id
312 WHERE staticipaddress.id = OLD.id OR staticipaddress.id = NEW.id)
313 LOOP
314- PERFORM pg_notify('domain_update',CAST(dom.domain_id AS text));
315+ PERFORM pg_notify('domain_update',CAST(dom.id AS text));
316 END LOOP;
317 END IF;
318 RETURN NEW;
319@@ -645,7 +647,7 @@
320 JOIN maasserver_interface AS interface ON
321 iia.interface_id = interface.id
322 JOIN maasserver_node AS node ON
323- node.boot_interface_id = interface.id) ON
324+ node.id = interface.node_id) ON
325 iia.staticipaddress_id = staticipaddress.id
326 LEFT JOIN (
327 maasserver_dnsresource_ip_addresses AS dia
328@@ -656,7 +658,7 @@
329 domain.id = node.domain_id OR domain.id = dnsresource.domain_id
330 WHERE staticipaddress.id = %s)
331 LOOP
332- PERFORM pg_notify('domain_update',CAST(dom.domain_id AS text));
333+ PERFORM pg_notify('domain_update',CAST(dom.id AS text));
334 END LOOP;
335 RETURN NEW;
336 END;
337@@ -667,14 +669,12 @@
338 DNSDATA_DOMAIN_NOTIFY = dedent("""\
339 CREATE OR REPLACE FUNCTION %s() RETURNS trigger AS $$
340 DECLARE
341- domain RECORD;
342+ dom RECORD;
343 BEGIN
344- SELECT DISTINCT ON (domain_id) domain_id INTO domain
345- FROM maasserver_dnsdata AS dnsdata
346- JOIN maasserver_dnsresource AS dnsresource ON
347- dnsresource.id = dnsdata.dnsresource_id
348- WHERE dnsdata.dnsresource_id = %s;
349- PERFORM pg_notify('domain_update',CAST(domain.domain_id AS text));
350+ SELECT DISTINCT ON (domain_id) domain_id INTO dom
351+ FROM maasserver_dnsresource AS dnsresource
352+ WHERE dnsresource.id = %s;
353+ PERFORM pg_notify('domain_update',CAST(dom.domain_id AS text));
354 RETURN NEW;
355 END;
356 $$ LANGUAGE plpgsql;
357@@ -1004,8 +1004,7 @@
358 register_procedure(
359 DNSDATA_DOMAIN_NOTIFY % (
360 'dnsdata_domain_update_notify',
361- 'NEW.dnsresource_id OR '
362- 'dnsdata.dnsresource_id = OLD.dnsresource_id'))
363+ 'OLD.dnsresource_id OR dnsresource.id = NEW.dnsresource_id'))
364 register_procedure(
365 DNSDATA_DOMAIN_NOTIFY % (
366 'dnsdata_domain_delete_notify', 'OLD.dnsresource_id'))