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

Proposed by Newell Jensen
Status: Merged
Approved by: Newell Jensen
Approved revision: 5456
Merged at revision: 5468
Proposed branch: lp:~newell-jensen/maas/fix-1608555-1631079
Merge into: lp:maas/trunk
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/fix-1608555-1631079
Reviewer Review Type Date Requested Status
Blake Rouse (community) Approve
Review via email: mp+307983@code.launchpad.net

Commit message

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

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

Looks good. But you are missing the triggers tests that should be added in triggers/tests/test_websocket_listener.py.

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

Looks good. Thanks for the tests.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/maasserver/static/js/angular/controllers/subnet_details.js'
--- src/maasserver/static/js/angular/controllers/subnet_details.js 2016-10-05 06:22:13 +0000
+++ src/maasserver/static/js/angular/controllers/subnet_details.js 2016-10-08 02:08:09 +0000
@@ -326,8 +326,6 @@
326 $scope.ipRangeConfirmDelete = function() {326 $scope.ipRangeConfirmDelete = function() {
327 IPRangesManager.deleteItem($scope.deleteIPRange).then(function() {327 IPRangesManager.deleteItem($scope.deleteIPRange).then(function() {
328 $scope.deleteIPRange = null;328 $scope.deleteIPRange = null;
329 // Reload the subnet after deleting the IP range.
330 $scope.subnet = SubnetsManager.getItem($scope.subnet.id);
331 });329 });
332 };330 };
333331
334332
=== modified file 'src/maasserver/static/js/angular/controllers/tests/test_subnet_details.js'
--- src/maasserver/static/js/angular/controllers/tests/test_subnet_details.js 2016-10-05 18:39:44 +0000
+++ src/maasserver/static/js/angular/controllers/tests/test_subnet_details.js 2016-10-08 02:08:09 +0000
@@ -565,15 +565,12 @@
565565
566 it("calls deleteItem and clears deleteIPRange on resolve", function() {566 it("calls deleteItem and clears deleteIPRange on resolve", function() {
567 var controller = makeController();567 var controller = makeController();
568 var subnet = makeSubnet();
569 var range = {};568 var range = {};
570 $scope.subnet = subnet;
571 $scope.deleteIPRange = range;569 $scope.deleteIPRange = range;
572570
573 var defer = $q.defer();571 var defer = $q.defer();
574 spyOn(IPRangesManager, "deleteItem").and.returnValue(572 spyOn(IPRangesManager, "deleteItem").and.returnValue(
575 defer.promise);573 defer.promise);
576 spyOn(SubnetsManager, "getItem");
577 $scope.ipRangeConfirmDelete();574 $scope.ipRangeConfirmDelete();
578575
579 expect(IPRangesManager.deleteItem).toHaveBeenCalledWith(range);576 expect(IPRangesManager.deleteItem).toHaveBeenCalledWith(range);
@@ -581,7 +578,6 @@
581 $scope.$digest();578 $scope.$digest();
582579
583 expect($scope.deleteIPRange).toBeNull();580 expect($scope.deleteIPRange).toBeNull();
584 expect(SubnetsManager.getItem).toHaveBeenCalledWith(subnet.id);
585 });581 });
586 });582 });
587583
588584
=== modified file 'src/maasserver/triggers/tests/test_websocket.py'
--- src/maasserver/triggers/tests/test_websocket.py 2016-09-22 02:53:33 +0000
+++ src/maasserver/triggers/tests/test_websocket.py 2016-10-08 02:08:09 +0000
@@ -99,6 +99,9 @@
99 "dhcpsnippet_dhcpsnippet_create_notify",99 "dhcpsnippet_dhcpsnippet_create_notify",
100 "dhcpsnippet_dhcpsnippet_update_notify",100 "dhcpsnippet_dhcpsnippet_update_notify",
101 "dhcpsnippet_dhcpsnippet_delete_notify",101 "dhcpsnippet_dhcpsnippet_delete_notify",
102 "iprange_iprange_subnet_insert_notify",
103 "iprange_iprange_subnet_update_notify",
104 "iprange_iprange_subnet_delete_notify",
102 ]105 ]
103 sql, args = psql_array(triggers, sql_type="text")106 sql, args = psql_array(triggers, sql_type="text")
104 with closing(connection.cursor()) as cursor:107 with closing(connection.cursor()) as cursor:
105108
=== modified file 'src/maasserver/triggers/tests/test_websocket_listener.py'
--- src/maasserver/triggers/tests/test_websocket_listener.py 2016-09-22 02:53:33 +0000
+++ src/maasserver/triggers/tests/test_websocket_listener.py 2016-10-08 02:08:09 +0000
@@ -13,6 +13,7 @@
13from crochet import wait_for13from crochet import wait_for
14from maasserver.enum import (14from maasserver.enum import (
15 IPADDRESS_TYPE,15 IPADDRESS_TYPE,
16 IPRANGE_TYPE,
16 NODE_TYPE,17 NODE_TYPE,
17)18)
18from maasserver.listener import PostgresListenerService19from maasserver.listener import PostgresListenerService
@@ -2980,6 +2981,127 @@
2980 yield listener.stopService()2981 yield listener.stopService()
29812982
29822983
2984class TestIPRangeSubnetListener(
2985 MAASTransactionServerTestCase, TransactionalHelpersMixin):
2986 """End-to-end test of both the listeners code and the triggers on
2987 maasserver_iprange tables that notifies affected subnets."""
2988
2989 @wait_for_reactor
2990 @inlineCallbacks
2991 def test__calls_handler_on_create_notification(self):
2992 yield deferToDatabase(register_websocket_triggers)
2993 subnet = yield deferToDatabase(
2994 self.create_subnet, {
2995 "cidr": '192.168.0.0/24',
2996 "gateway_ip": '192.168.0.1',
2997 "dns_servers": [],
2998 })
2999
3000 listener = PostgresListenerService()
3001 dv = DeferredValue()
3002 listener.register("subnet", lambda *args: dv.set(args))
3003 yield listener.startService()
3004 try:
3005 iprange = yield deferToDatabase(
3006 self.create_iprange, {
3007 "type": IPRANGE_TYPE.DYNAMIC,
3008 "subnet": subnet,
3009 "start_ip": '192.168.0.100',
3010 "end_ip": '192.168.0.110',
3011 })
3012 yield dv.get(timeout=2)
3013 self.assertEqual(('update', '%s' % iprange.subnet.id), dv.value)
3014 finally:
3015 yield listener.stopService()
3016
3017 @wait_for_reactor
3018 @inlineCallbacks
3019 def test__calls_handler_on_update_notification(self):
3020 yield deferToDatabase(register_websocket_triggers)
3021 iprange = yield deferToDatabase(self.create_iprange)
3022 new_end_ip = factory.pick_ip_in_IPRange(iprange)
3023
3024 listener = PostgresListenerService()
3025 dv = DeferredValue()
3026 listener.register("subnet", lambda *args: dv.set(args))
3027 yield listener.startService()
3028 try:
3029 yield deferToDatabase(
3030 self.update_iprange,
3031 iprange.id, {"end_ip": new_end_ip})
3032 yield dv.get(timeout=2)
3033 self.assertEqual(('update', '%s' % iprange.subnet.id), dv.value)
3034 finally:
3035 yield listener.stopService()
3036
3037 @wait_for_reactor
3038 @inlineCallbacks
3039 def test__calls_handler_on_update_on_old_and_new_subnet_notification(self):
3040 yield deferToDatabase(register_websocket_triggers)
3041 old_subnet = yield deferToDatabase(
3042 self.create_subnet, {
3043 "cidr": '192.168.0.0/24',
3044 "gateway_ip": '192.168.0.1',
3045 "dns_servers": [],
3046 })
3047 new_subnet = yield deferToDatabase(
3048 self.create_subnet, {
3049 "cidr": '192.168.1.0/24',
3050 "gateway_ip": '192.168.1.1',
3051 "dns_servers": [],
3052 })
3053 iprange = yield deferToDatabase(
3054 self.create_iprange, {
3055 "type": IPRANGE_TYPE.DYNAMIC,
3056 "subnet": old_subnet,
3057 "start_ip": '192.168.0.100',
3058 "end_ip": '192.168.0.110',
3059 })
3060 dvs = [DeferredValue(), DeferredValue()]
3061
3062 def set_defer_value(*args):
3063 for dv in dvs:
3064 if not dv.isSet:
3065 dv.set(args)
3066 break
3067
3068 listener = PostgresListenerService()
3069 listener.register("subnet", set_defer_value)
3070 yield listener.startService()
3071 try:
3072 yield deferToDatabase(self.update_iprange, iprange.id, {
3073 "type": IPRANGE_TYPE.DYNAMIC,
3074 "subnet": new_subnet,
3075 "start_ip": '192.168.1.10',
3076 "end_ip": '192.168.1.150',
3077 })
3078 yield dvs[0].get(timeout=2)
3079 yield dvs[1].get(timeout=2)
3080 self.assertItemsEqual([
3081 ('update', '%s' % old_subnet.id),
3082 ('update', '%s' % new_subnet.id),
3083 ], [dvs[0].value, dvs[1].value])
3084 finally:
3085 yield listener.stopService()
3086
3087 @wait_for_reactor
3088 @inlineCallbacks
3089 def test__calls_handler_on_delete_notification(self):
3090 yield deferToDatabase(register_websocket_triggers)
3091 iprange = yield deferToDatabase(self.create_iprange)
3092
3093 listener = PostgresListenerService()
3094 dv = DeferredValue()
3095 listener.register("subnet", lambda *args: dv.set(args))
3096 yield listener.startService()
3097 try:
3098 yield deferToDatabase(self.delete_iprange, iprange.id)
3099 yield dv.get(timeout=2)
3100 self.assertEqual(('update', '%s' % iprange.subnet.id), dv.value)
3101 finally:
3102 yield listener.stopService()
3103
3104
2983class TestNodeTypeChange(3105class TestNodeTypeChange(
2984 MAASTransactionServerTestCase, TransactionalHelpersMixin):3106 MAASTransactionServerTestCase, TransactionalHelpersMixin):
2985 """End-to-end test of node type change triggers code."""3107 """End-to-end test of node type change triggers code."""
29863108
=== modified file 'src/maasserver/triggers/websocket.py'
--- src/maasserver/triggers/websocket.py 2016-09-22 02:53:33 +0000
+++ src/maasserver/triggers/websocket.py 2016-10-08 02:08:09 +0000
@@ -687,6 +687,50 @@
687 $$ LANGUAGE plpgsql;687 $$ LANGUAGE plpgsql;
688 """)688 """)
689689
690# Procedure that is called when an IP range is created to update its related
691# subnet.
692IP_RANGE_SUBNET_INSERT_NOTIFY = dedent("""\
693 CREATE OR REPLACE FUNCTION %s() RETURNS trigger AS $$
694 BEGIN
695 IF NEW.subnet_id IS NOT NULL THEN
696 PERFORM pg_notify('subnet_update',CAST(NEW.subnet_id AS text));
697 END IF;
698 RETURN NEW;
699 END;
700 $$ LANGUAGE plpgsql;
701 """)
702
703# Procedure that is called when an IP range is updated to update its related
704# subnet.
705IP_RANGE_SUBNET_UPDATE_NOTIFY = dedent("""\
706 CREATE OR REPLACE FUNCTION %s() RETURNS trigger AS $$
707 BEGIN
708 IF OLD.subnet_id != NEW.subnet_id THEN
709 IF OLD.subnet_id IS NOT NULL THEN
710 PERFORM pg_notify('subnet_update',CAST(OLD.subnet_id AS text));
711 END IF;
712 END IF;
713 IF NEW.subnet_id IS NOT NULL THEN
714 PERFORM pg_notify('subnet_update',CAST(NEW.subnet_id AS text));
715 END IF;
716 RETURN NEW;
717 END;
718 $$ LANGUAGE plpgsql;
719 """)
720
721# Procedure that is called when an IP range is deleted to update its related
722# subnet.
723IP_RANGE_SUBNET_DELETE_NOTIFY = dedent("""\
724 CREATE OR REPLACE FUNCTION %s() RETURNS trigger AS $$
725 BEGIN
726 IF OLD.subnet_id IS NOT NULL THEN
727 PERFORM pg_notify('subnet_update',CAST(OLD.subnet_id AS text));
728 END IF;
729 RETURN OLD;
730 END;
731 $$ LANGUAGE plpgsql;
732 """)
733
690# Procedure that is called when a DNSData entry is changed.734# Procedure that is called when a DNSData entry is changed.
691DNSDATA_DOMAIN_NOTIFY = dedent("""\735DNSDATA_DOMAIN_NOTIFY = dedent("""\
692 CREATE OR REPLACE FUNCTION %s() RETURNS trigger AS $$736 CREATE OR REPLACE FUNCTION %s() RETURNS trigger AS $$
@@ -1134,6 +1178,23 @@
1134 "maasserver_staticipaddress",1178 "maasserver_staticipaddress",
1135 "ipaddress_domain_delete_notify", "delete")1179 "ipaddress_domain_delete_notify", "delete")
11361180
1181 # IP range subnet notifications
1182 register_procedure(
1183 IP_RANGE_SUBNET_INSERT_NOTIFY % 'iprange_subnet_insert_notify')
1184 register_procedure(
1185 IP_RANGE_SUBNET_UPDATE_NOTIFY % 'iprange_subnet_update_notify')
1186 register_procedure(
1187 IP_RANGE_SUBNET_DELETE_NOTIFY % 'iprange_subnet_delete_notify')
1188 register_trigger(
1189 "maasserver_iprange",
1190 "iprange_subnet_insert_notify", "insert")
1191 register_trigger(
1192 "maasserver_iprange",
1193 "iprange_subnet_update_notify", "update")
1194 register_trigger(
1195 "maasserver_iprange",
1196 "iprange_subnet_delete_notify", "delete")
1197
1137 # DNSData table1198 # DNSData table
1138 register_procedure(1199 register_procedure(
1139 DNSDATA_DOMAIN_NOTIFY % (1200 DNSDATA_DOMAIN_NOTIFY % (