Merge lp:~newell-jensen/maas/2.0-fix-1608555-1631079 into lp:maas/2.0

Proposed by Newell Jensen on 2016-10-11
Status: Merged
Approved by: Newell Jensen on 2016-10-11
Approved revision: 5197
Merged at revision: 5197
Proposed branch: lp:~newell-jensen/maas/2.0-fix-1608555-1631079
Merge into: lp:maas/2.0
Diff against target: 273 lines (+186/-6)
5 files modified
src/maasserver/static/js/angular/controllers/subnet_details.js (+0/-2)
src/maasserver/static/js/angular/controllers/tests/test_subnet_details.js (+0/-4)
src/maasserver/triggers/tests/test_websocket.py (+3/-0)
src/maasserver/triggers/tests/test_websocket_listener.py (+122/-0)
src/maasserver/triggers/websocket.py (+61/-0)
To merge this branch: bzr merge lp:~newell-jensen/maas/2.0-fix-1608555-1631079
Reviewer Review Type Date Requested Status
Newell Jensen Approve on 2016-10-11
Review via email: mp+308198@code.launchpad.net

Commit message

Backport trunk r5468: Add triggers for updating a subnet when it's IP range is created/updated/deleted.

To post a comment you must log in.
Newell Jensen (newell-jensen) wrote :

Self approved backport.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/static/js/angular/controllers/subnet_details.js'
2--- src/maasserver/static/js/angular/controllers/subnet_details.js 2016-10-05 20:30:53 +0000
3+++ src/maasserver/static/js/angular/controllers/subnet_details.js 2016-10-11 21:19:50 +0000
4@@ -244,8 +244,6 @@
5 $scope.ipRangeConfirmDelete = function() {
6 IPRangesManager.deleteItem($scope.deleteIPRange).then(function() {
7 $scope.deleteIPRange = null;
8- // Reload the subnet after deleting the IP range.
9- $scope.subnet = SubnetsManager.getItem($scope.subnet.id);
10 });
11 };
12
13
14=== modified file 'src/maasserver/static/js/angular/controllers/tests/test_subnet_details.js'
15--- src/maasserver/static/js/angular/controllers/tests/test_subnet_details.js 2016-10-05 20:30:53 +0000
16+++ src/maasserver/static/js/angular/controllers/tests/test_subnet_details.js 2016-10-11 21:19:50 +0000
17@@ -601,15 +601,12 @@
18
19 it("calls deleteItem and clears deleteIPRange on resolve", function() {
20 var controller = makeController();
21- var subnet = makeSubnet();
22 var range = {};
23- $scope.subnet = subnet;
24 $scope.deleteIPRange = range;
25
26 var defer = $q.defer();
27 spyOn(IPRangesManager, "deleteItem").and.returnValue(
28 defer.promise);
29- spyOn(SubnetsManager, "getItem");
30 $scope.ipRangeConfirmDelete();
31
32 expect(IPRangesManager.deleteItem).toHaveBeenCalledWith(range);
33@@ -617,7 +614,6 @@
34 $scope.$digest();
35
36 expect($scope.deleteIPRange).toBeNull();
37- expect(SubnetsManager.getItem).toHaveBeenCalledWith(subnet.id);
38 });
39 });
40 });
41
42=== modified file 'src/maasserver/triggers/tests/test_websocket.py'
43--- src/maasserver/triggers/tests/test_websocket.py 2016-06-10 19:32:52 +0000
44+++ src/maasserver/triggers/tests/test_websocket.py 2016-10-11 21:19:50 +0000
45@@ -90,6 +90,9 @@
46 "dhcpsnippet_dhcpsnippet_create_notify",
47 "dhcpsnippet_dhcpsnippet_update_notify",
48 "dhcpsnippet_dhcpsnippet_delete_notify",
49+ "iprange_iprange_subnet_insert_notify",
50+ "iprange_iprange_subnet_update_notify",
51+ "iprange_iprange_subnet_delete_notify",
52 ]
53 sql, args = psql_array(triggers, sql_type="text")
54 with closing(connection.cursor()) as cursor:
55
56=== modified file 'src/maasserver/triggers/tests/test_websocket_listener.py'
57--- src/maasserver/triggers/tests/test_websocket_listener.py 2016-06-14 16:43:53 +0000
58+++ src/maasserver/triggers/tests/test_websocket_listener.py 2016-10-11 21:19:50 +0000
59@@ -13,6 +13,7 @@
60 from crochet import wait_for
61 from maasserver.enum import (
62 IPADDRESS_TYPE,
63+ IPRANGE_TYPE,
64 NODE_TYPE,
65 )
66 from maasserver.listener import PostgresListenerService
67@@ -2726,6 +2727,127 @@
68 yield listener.stopService()
69
70
71+class TestIPRangeSubnetListener(
72+ MAASTransactionServerTestCase, TransactionalHelpersMixin):
73+ """End-to-end test of both the listeners code and the triggers on
74+ maasserver_iprange tables that notifies affected subnets."""
75+
76+ @wait_for_reactor
77+ @inlineCallbacks
78+ def test__calls_handler_on_create_notification(self):
79+ yield deferToDatabase(register_websocket_triggers)
80+ subnet = yield deferToDatabase(
81+ self.create_subnet, {
82+ "cidr": '192.168.0.0/24',
83+ "gateway_ip": '192.168.0.1',
84+ "dns_servers": [],
85+ })
86+
87+ listener = PostgresListenerService()
88+ dv = DeferredValue()
89+ listener.register("subnet", lambda *args: dv.set(args))
90+ yield listener.startService()
91+ try:
92+ iprange = yield deferToDatabase(
93+ self.create_iprange, {
94+ "type": IPRANGE_TYPE.DYNAMIC,
95+ "subnet": subnet,
96+ "start_ip": '192.168.0.100',
97+ "end_ip": '192.168.0.110',
98+ })
99+ yield dv.get(timeout=2)
100+ self.assertEqual(('update', '%s' % iprange.subnet.id), dv.value)
101+ finally:
102+ yield listener.stopService()
103+
104+ @wait_for_reactor
105+ @inlineCallbacks
106+ def test__calls_handler_on_update_notification(self):
107+ yield deferToDatabase(register_websocket_triggers)
108+ iprange = yield deferToDatabase(self.create_iprange)
109+ new_end_ip = factory.pick_ip_in_IPRange(iprange)
110+
111+ listener = PostgresListenerService()
112+ dv = DeferredValue()
113+ listener.register("subnet", lambda *args: dv.set(args))
114+ yield listener.startService()
115+ try:
116+ yield deferToDatabase(
117+ self.update_iprange,
118+ iprange.id, {"end_ip": new_end_ip})
119+ yield dv.get(timeout=2)
120+ self.assertEqual(('update', '%s' % iprange.subnet.id), dv.value)
121+ finally:
122+ yield listener.stopService()
123+
124+ @wait_for_reactor
125+ @inlineCallbacks
126+ def test__calls_handler_on_update_on_old_and_new_subnet_notification(self):
127+ yield deferToDatabase(register_websocket_triggers)
128+ old_subnet = yield deferToDatabase(
129+ self.create_subnet, {
130+ "cidr": '192.168.0.0/24',
131+ "gateway_ip": '192.168.0.1',
132+ "dns_servers": [],
133+ })
134+ new_subnet = yield deferToDatabase(
135+ self.create_subnet, {
136+ "cidr": '192.168.1.0/24',
137+ "gateway_ip": '192.168.1.1',
138+ "dns_servers": [],
139+ })
140+ iprange = yield deferToDatabase(
141+ self.create_iprange, {
142+ "type": IPRANGE_TYPE.DYNAMIC,
143+ "subnet": old_subnet,
144+ "start_ip": '192.168.0.100',
145+ "end_ip": '192.168.0.110',
146+ })
147+ dvs = [DeferredValue(), DeferredValue()]
148+
149+ def set_defer_value(*args):
150+ for dv in dvs:
151+ if not dv.isSet:
152+ dv.set(args)
153+ break
154+
155+ listener = PostgresListenerService()
156+ listener.register("subnet", set_defer_value)
157+ yield listener.startService()
158+ try:
159+ yield deferToDatabase(self.update_iprange, iprange.id, {
160+ "type": IPRANGE_TYPE.DYNAMIC,
161+ "subnet": new_subnet,
162+ "start_ip": '192.168.1.10',
163+ "end_ip": '192.168.1.150',
164+ })
165+ yield dvs[0].get(timeout=2)
166+ yield dvs[1].get(timeout=2)
167+ self.assertItemsEqual([
168+ ('update', '%s' % old_subnet.id),
169+ ('update', '%s' % new_subnet.id),
170+ ], [dvs[0].value, dvs[1].value])
171+ finally:
172+ yield listener.stopService()
173+
174+ @wait_for_reactor
175+ @inlineCallbacks
176+ def test__calls_handler_on_delete_notification(self):
177+ yield deferToDatabase(register_websocket_triggers)
178+ iprange = yield deferToDatabase(self.create_iprange)
179+
180+ listener = PostgresListenerService()
181+ dv = DeferredValue()
182+ listener.register("subnet", lambda *args: dv.set(args))
183+ yield listener.startService()
184+ try:
185+ yield deferToDatabase(self.delete_iprange, iprange.id)
186+ yield dv.get(timeout=2)
187+ self.assertEqual(('update', '%s' % iprange.subnet.id), dv.value)
188+ finally:
189+ yield listener.stopService()
190+
191+
192 class TestNodeTypeChange(
193 MAASTransactionServerTestCase, TransactionalHelpersMixin):
194 """End-to-end test of node type change triggers code."""
195
196=== modified file 'src/maasserver/triggers/websocket.py'
197--- src/maasserver/triggers/websocket.py 2016-06-10 18:53:59 +0000
198+++ src/maasserver/triggers/websocket.py 2016-10-11 21:19:50 +0000
199@@ -687,6 +687,50 @@
200 $$ LANGUAGE plpgsql;
201 """)
202
203+# Procedure that is called when an IP range is created to update its related
204+# subnet.
205+IP_RANGE_SUBNET_INSERT_NOTIFY = dedent("""\
206+ CREATE OR REPLACE FUNCTION %s() RETURNS trigger AS $$
207+ BEGIN
208+ IF NEW.subnet_id IS NOT NULL THEN
209+ PERFORM pg_notify('subnet_update',CAST(NEW.subnet_id AS text));
210+ END IF;
211+ RETURN NEW;
212+ END;
213+ $$ LANGUAGE plpgsql;
214+ """)
215+
216+# Procedure that is called when an IP range is updated to update its related
217+# subnet.
218+IP_RANGE_SUBNET_UPDATE_NOTIFY = dedent("""\
219+ CREATE OR REPLACE FUNCTION %s() RETURNS trigger AS $$
220+ BEGIN
221+ IF OLD.subnet_id != NEW.subnet_id THEN
222+ IF OLD.subnet_id IS NOT NULL THEN
223+ PERFORM pg_notify('subnet_update',CAST(OLD.subnet_id AS text));
224+ END IF;
225+ END IF;
226+ IF NEW.subnet_id IS NOT NULL THEN
227+ PERFORM pg_notify('subnet_update',CAST(NEW.subnet_id AS text));
228+ END IF;
229+ RETURN NEW;
230+ END;
231+ $$ LANGUAGE plpgsql;
232+ """)
233+
234+# Procedure that is called when an IP range is deleted to update its related
235+# subnet.
236+IP_RANGE_SUBNET_DELETE_NOTIFY = dedent("""\
237+ CREATE OR REPLACE FUNCTION %s() RETURNS trigger AS $$
238+ BEGIN
239+ IF OLD.subnet_id IS NOT NULL THEN
240+ PERFORM pg_notify('subnet_update',CAST(OLD.subnet_id AS text));
241+ END IF;
242+ RETURN OLD;
243+ END;
244+ $$ LANGUAGE plpgsql;
245+ """)
246+
247 # Procedure that is called when a DNSData entry is changed.
248 DNSDATA_DOMAIN_NOTIFY = dedent("""\
249 CREATE OR REPLACE FUNCTION %s() RETURNS trigger AS $$
250@@ -1100,6 +1144,23 @@
251 "maasserver_staticipaddress",
252 "ipaddress_domain_delete_notify", "delete")
253
254+ # IP range subnet notifications
255+ register_procedure(
256+ IP_RANGE_SUBNET_INSERT_NOTIFY % 'iprange_subnet_insert_notify')
257+ register_procedure(
258+ IP_RANGE_SUBNET_UPDATE_NOTIFY % 'iprange_subnet_update_notify')
259+ register_procedure(
260+ IP_RANGE_SUBNET_DELETE_NOTIFY % 'iprange_subnet_delete_notify')
261+ register_trigger(
262+ "maasserver_iprange",
263+ "iprange_subnet_insert_notify", "insert")
264+ register_trigger(
265+ "maasserver_iprange",
266+ "iprange_subnet_update_notify", "update")
267+ register_trigger(
268+ "maasserver_iprange",
269+ "iprange_subnet_delete_notify", "delete")
270+
271 # DNSData table
272 register_procedure(
273 DNSDATA_DOMAIN_NOTIFY % (

Subscribers

People subscribed via source and target branches

to all changes: