Merge lp:~allenap/maas/chassis-delete-and-create-trigger into lp:~maas-committers/maas/trunk

Proposed by Gavin Panella
Status: Merged
Approved by: Gavin Panella
Approved revision: no longer in the source branch.
Merged at revision: 5632
Proposed branch: lp:~allenap/maas/chassis-delete-and-create-trigger
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 407 lines (+226/-142)
4 files modified
src/maasserver/models/signals/nodes.py (+3/-8)
src/maasserver/models/signals/tests/test_nodes.py (+3/-6)
src/maasserver/triggers/tests/test_init.py (+220/-1)
src/maasserver/triggers/tests/test_websocket.py (+0/-127)
To merge this branch: bzr merge lp:~allenap/maas/chassis-delete-and-create-trigger
Reviewer Review Type Date Requested Status
Blake Rouse (community) Approve
Review via email: mp+314161@code.launchpad.net

Commit message

In the node_type_change_notify trigger, explicitly do nothing when a node is converted to or from a chassis.

There are some related drive-by fixes and simplifications too.

Description of the change

Most of this branch is drive-by changes. However...

The interesting bit is in src/maasserver/triggers/websocket.py where I've changed the node_type_change_notify trigger function to do nothing when the node is or was a chassis. This was causing test failures in TestCreateChassisHints in another branch (lp:~allenap/maas/non-django-database-test) where the CASE statement was hitting END CASE without branching; this is an error in PL/pgSQL. I haven't figured out why this failure is only observed when using that branch's new database set-up mechanism.

Nevertheless, this is an omission. I originally added a PERFORM pg_notify(...) here, but this opened other cans of worms. Most notably I tried adding a couple of scenarios — device_to_chassis and chassis_to_device — to TestNodeTypeChange but the former failed with a time-out. It turns out that nothing is sending a chassis_update message. I attempt to add that in register_websocket_triggers and realised (a) there's overlap between the triggers that are created near the start of that function (which send out, for example, machine_create and machine_delete) and the node_type_change_notify trigger function I mentioned earlier (which also sends machine_create and machine_delete).

Comments in the code are sparse. What tests there are do not give me answers. I had no idea if I should continue along this path, so I chose the least can-of-worms option I could, which is to explicitly do nothing in node_type_change_notify.

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

This is actual fine since a machine or any other node type will not be converted to a chassis. Chassis are always created explicitly.

Thanks for the cleanup of the ChassisHints!

review: Approve
Revision history for this message
Gavin Panella (allenap) wrote :

Thanks Blake.

Should I be concerned about the overlap between node_type_change_notify
and those at the top of register_websocket_triggers?

  @transactional
  def register_websocket_triggers():
      """Register all websocket triggers into the database."""

      for (proc_name_prefix, event_name_prefix, node_type) in (
          ('machine', 'machine', NODE_TYPE.MACHINE),
          ('rack_controller', 'controller', NODE_TYPE.RACK_CONTROLLER),
          ('region_controller', 'controller', NODE_TYPE.REGION_CONTROLLER),
          ('region_and_rack_controller', 'controller',
           NODE_TYPE.REGION_AND_RACK_CONTROLLER)):

          # Non-Device Node types
          register_procedure(
              render_notification_procedure(
                  '%s_create_notify' % proc_name_prefix,
-->               '%s_create' % event_name_prefix,
                  'NEW.system_id'))
          register_procedure(
              render_notification_procedure(
                  '%s_update_notify' % proc_name_prefix,
                  '%s_update' % event_name_prefix,
                  'NEW.system_id'))
          register_procedure(
              render_notification_procedure(
                  '%s_delete_notify' % proc_name_prefix,
-->               '%s_delete' % event_name_prefix,
                  'OLD.system_id'))
          register_trigger(
              "maasserver_node",
              "%s_create_notify" % proc_name_prefix,
              "insert",
              {'NEW.node_type': node_type})
          register_trigger(
              "maasserver_node",
              "%s_update_notify" % proc_name_prefix,
              "update",
              {'NEW.node_type': node_type})
          register_trigger(
              "maasserver_node",
              "%s_delete_notify" % proc_name_prefix,
              "delete",
              {'OLD.node_type': node_type})
      ...

Either or both the database and the listener will deduplicate these, but
it still looks like duplicated work. If that's by design we should leave
some comments behind so that my forgetful mind doesn't come back to this
like a goldfish circling the tank.

Revision history for this message
Gavin Panella (allenap) wrote :

I'll land this now, but the question of overlap still stands.

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

I am confused? Can you explain this a little more?

Do the procedures overlap in name?

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

The attempt to merge lp:~allenap/maas/chassis-delete-and-create-trigger into lp:maas failed. Below is the output from the failed tests.

Hit:1 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial InRelease
Get:2 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates InRelease [102 kB]
Get:3 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-backports InRelease [102 kB]
Get:4 http://security.ubuntu.com/ubuntu xenial-security InRelease [102 kB]
Fetched 306 kB in 0s (624 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
    --no-install-recommends install apache2 archdetect-deb authbind avahi-utils bash bind9 bind9utils build-essential bzr 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 isc-dhcp-server libjs-angularjs libjs-jquery libjs-jquery-hotkeys libjs-yui3-full libjs-yui3-min libnss-wrapper libpq-dev make nodejs-legacy npm postgresql pxelinux python3-all python3-apt python3-attr python3-bson python3-convoy 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-netaddr python3-netifaces python3-novaclient 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-simplejson python-tempita python-twisted python-yaml socat syslinux-common tgt ubuntu-cloudimage-keyring wget xvfb
Reading package lists...
Building dependency tree...
Reading state information...
authbind is already the newest version (2.1.1+nmu1).
avahi-utils is already the newest version (0.6.32~rc+dfsg-1ubuntu2).
build-essential is already the newest version (12.1ubuntu2).
debhelper is already the newest version (9.20160115ubuntu3).
distro-info is already the newest version (0.14build1).
git is already the newest version (1:2.7.4-0ubuntu1).
libjs-angularjs is already the newest version (1.2.28-1ubuntu2).
libjs-jquery is already the newest version (1.11.3+dfsg-4).
libjs-yui3-full is already the newest version (3.5.1-1ubuntu3).
libjs-yui3-min is already the newest version (3.5.1-1ubuntu3).
make is already the newest version (4.1-6).
postgresql is already the newest version (9.5+173).
pxelinux is already the newest version (3:6.03+dfsg-11ubuntu1).
python-formencode is already the newest version (1.3.0-0ubuntu5).
python-lxml is already the newest version (3.5.0-1build1).
python-netaddr is already the newest version (0.7.18-1).
python-netifaces is already the newest version (0.10.4-0.1build...

Revision history for this message
Gavin Panella (allenap) wrote :

This branch was based on a pre-non-Django-tests branch and the trigger
tests were based on some outdated assumptions. I've reformulated those.

Revision history for this message
Gavin Panella (allenap) wrote :
Download full text (3.7 KiB)

Blake wrote:
> I am confused? Can you explain this a little more?
>
> Do the procedures overlap in name?

There are many triggers on maasserver_node, but the following will
illustrate the overlap:

First is the trigger that calls node_type_change_notify when there's any
update:

  node_node_type_change_notify
    AFTER UPDATE ON maasserver_node
      FOR EACH ROW
      EXECUTE PROCEDURE node_type_change_notify()

The node_type_change_notify procedure can issue NOTIFYs with the
following pattern:

  {machine,device,controller}_{delete,create}

The other interesting triggers on maasserver_node are:

  node_device_update_notify
    AFTER UPDATE ON maasserver_node
      FOR EACH ROW WHEN (new.node_type = 1)
      EXECUTE PROCEDURE device_update_notify()

  node_machine_update_notify
    AFTER UPDATE ON maasserver_node
      FOR EACH ROW WHEN (new.node_type = 0)
      EXECUTE PROCEDURE machine_update_notify()

  node_rack_controller_update_notify
    AFTER UPDATE ON maasserver_node
      FOR EACH ROW WHEN (new.node_type = 2)
      EXECUTE PROCEDURE rack_controller_update_notify()

  node_region_and_rack_controller_update_notify
    AFTER UPDATE ON maasserver_node
      FOR EACH ROW WHEN (new.node_type = 4)
      EXECUTE PROCEDURE region_and_rack_controller_update_notify()

  node_region_controller_update_notify
    AFTER UPDATE ON maasserver_node
      FOR EACH ROW WHEN (new.node_type = 3)
      EXECUTE PROCEDURE region_controller_update_notify()

Take machine_update_notify as an example:

  DECLARE
  BEGIN
    PERFORM pg_notify('machine_update',CAST(NEW.system_id AS text));
    RETURN NEW;
  END;

So, when a node is converted from, say, a rack controller to a machine,
the following messages will be NOTIFY'ed:

  machine_update (via node_machine_update_notify)
  controller_delete (via node_node_type_change_notify)
  machine_create (via node_node_type_change_notify)

This is a confusing order for things to appear in: the update before the
create.

FWIW, the order is stable: PostgreSQL says that NOTIFY'ed messages are
delivered in order [1] and triggers are run in alphabetical order [2].

Converting back from a machine to a rack controller will, I think,
result in:

  machine_delete (via node_node_type_change_notify)
  controller_create (via node_node_type_change_notify)
  controller_update (via node_rack_controller_update_notify)

This is a more sensible order, but it also differs from before. The
presence of both *_create and *_update messages in both examples is also
repetition: both messages arise from the same event, an update.

Now, I don't know of anything that depends on this ordering, but I also
don't know all of the code. A few things stand out:

- We may already have bugs related to this ordering.

- We may create bugs related to this ordering in future.

- It's hard to figure all of MAAS's trigger stuff out.

I don't have an answer to this, but I do think that the way we compose
procedures and triggers has been outgrown by the complexity of the
systems that are reliant upon it. There are still manual steps required
to join up all the pieces. I'd like to be able to say it declaritively,
like:

  When a row in table foo is u...

Read more...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/models/signals/nodes.py'
2--- src/maasserver/models/signals/nodes.py 2017-01-03 19:37:46 +0000
3+++ src/maasserver/models/signals/nodes.py 2017-01-10 13:35:41 +0000
4@@ -115,15 +115,10 @@
5
6 def create_chassis_hints(sender, instance, created, **kwargs):
7 """Create `ChassisHints` when `Chassis` is created."""
8- try:
9- chassis_hints = instance.chassis_hints
10- except ChassisHints.DoesNotExist:
11- chassis_hints = None
12 if instance.node_type == NODE_TYPE.CHASSIS:
13- if chassis_hints is None:
14- ChassisHints.objects.create(chassis=instance)
15- elif chassis_hints is not None:
16- chassis_hints.delete()
17+ ChassisHints.objects.get_or_create(chassis=instance)
18+ else:
19+ ChassisHints.objects.filter(chassis=instance).delete()
20
21 for klass in NODE_CLASSES:
22 signals.watch(
23
24=== modified file 'src/maasserver/models/signals/tests/test_nodes.py'
25--- src/maasserver/models/signals/tests/test_nodes.py 2017-01-05 15:21:29 +0000
26+++ src/maasserver/models/signals/tests/test_nodes.py 2017-01-10 13:35:41 +0000
27@@ -163,9 +163,6 @@
28 chassis = factory.make_Node(node_type=NODE_TYPE.CHASSIS)
29 chassis.node_type = NODE_TYPE.DEVICE
30 chassis.save()
31- error = None
32- try:
33- reload_object(chassis).chassis_hints
34- except ChassisHints.DoesNotExist as exc:
35- error = exc
36- self.assertIsNotNone(error)
37+ self.assertRaises(
38+ ChassisHints.DoesNotExist,
39+ lambda: chassis.chassis_hints)
40
41=== modified file 'src/maasserver/triggers/tests/test_init.py'
42--- src/maasserver/triggers/tests/test_init.py 2016-03-28 13:54:47 +0000
43+++ src/maasserver/triggers/tests/test_init.py 2017-01-10 13:35:41 +0000
44@@ -13,7 +13,15 @@
45 register_procedure,
46 register_trigger,
47 )
48-from maasserver.triggers.websocket import render_notification_procedure
49+from maasserver.triggers.system import register_system_triggers
50+from maasserver.triggers.websocket import (
51+ register_websocket_triggers,
52+ render_notification_procedure,
53+)
54+from testtools.matchers import Equals
55+
56+
57+EMPTY_SET = frozenset()
58
59
60 class TestTriggers(MAASServerTestCase):
61@@ -46,3 +54,214 @@
62 triggers = cursor.fetchall()
63
64 self.assertEqual(1, len(triggers), "Trigger was not created.")
65+
66+
67+class TestTriggersUsed(MAASServerTestCase):
68+ """Tests relating to those triggers the MAAS application uses."""
69+
70+ triggers_system = {
71+ "config_sys_dhcp_config_ntp_servers_delete",
72+ "config_sys_dhcp_config_ntp_servers_insert",
73+ "config_sys_dhcp_config_ntp_servers_update",
74+ "config_sys_dns_config_insert",
75+ "config_sys_dns_config_update",
76+ "dhcpsnippet_sys_dhcp_snippet_delete",
77+ "dhcpsnippet_sys_dhcp_snippet_insert",
78+ "dhcpsnippet_sys_dhcp_snippet_update",
79+ "dnsdata_sys_dns_dnsdata_delete",
80+ "dnsdata_sys_dns_dnsdata_insert",
81+ "dnsdata_sys_dns_dnsdata_update",
82+ "dnspublication_sys_dns_publish",
83+ "dnsresource_ip_addresses_sys_dns_dnsresource_ip_link",
84+ "dnsresource_ip_addresses_sys_dns_dnsresource_ip_unlink",
85+ "dnsresource_sys_dns_dnsresource_delete",
86+ "dnsresource_sys_dns_dnsresource_insert",
87+ "dnsresource_sys_dns_dnsresource_update",
88+ "domain_sys_dns_domain_delete",
89+ "domain_sys_dns_domain_insert",
90+ "domain_sys_dns_domain_update",
91+ "interface_ip_addresses_sys_dns_nic_ip_link",
92+ "interface_ip_addresses_sys_dns_nic_ip_unlink",
93+ "interface_sys_dhcp_interface_update",
94+ "interface_sys_dns_interface_update",
95+ "iprange_sys_dhcp_iprange_delete",
96+ "iprange_sys_dhcp_iprange_insert",
97+ "iprange_sys_dhcp_iprange_update",
98+ "node_sys_dhcp_node_update",
99+ "node_sys_dns_node_delete",
100+ "node_sys_dns_node_update",
101+ "regionrackrpcconnection_sys_core_rpc_delete",
102+ "regionrackrpcconnection_sys_core_rpc_insert",
103+ "staticipaddress_sys_dhcp_staticipaddress_delete",
104+ "staticipaddress_sys_dhcp_staticipaddress_insert",
105+ "staticipaddress_sys_dhcp_staticipaddress_update",
106+ "staticipaddress_sys_dns_staticipaddress_update",
107+ "subnet_sys_dhcp_subnet_delete",
108+ "subnet_sys_dhcp_subnet_update",
109+ "subnet_sys_dns_subnet_delete",
110+ "subnet_sys_dns_subnet_insert",
111+ "subnet_sys_dns_subnet_update",
112+ "subnet_sys_proxy_subnet_delete",
113+ "subnet_sys_proxy_subnet_insert",
114+ "subnet_sys_proxy_subnet_update",
115+ "vlan_sys_dhcp_vlan_update",
116+ }
117+
118+ triggers_websocket = {
119+ "auth_user_user_create_notify",
120+ "auth_user_user_delete_notify",
121+ "auth_user_user_update_notify",
122+ "blockdevice_nd_blockdevice_link_notify",
123+ "blockdevice_nd_blockdevice_unlink_notify",
124+ "blockdevice_nd_blockdevice_update_notify",
125+ "cacheset_nd_cacheset_link_notify",
126+ "cacheset_nd_cacheset_unlink_notify",
127+ "cacheset_nd_cacheset_update_notify",
128+ "config_config_create_notify",
129+ "config_config_delete_notify",
130+ "config_config_update_notify",
131+ "dhcpsnippet_dhcpsnippet_create_notify",
132+ "dhcpsnippet_dhcpsnippet_delete_notify",
133+ "dhcpsnippet_dhcpsnippet_update_notify",
134+ "dnsdata_dnsdata_domain_delete_notify",
135+ "dnsdata_dnsdata_domain_insert_notify",
136+ "dnsdata_dnsdata_domain_update_notify",
137+ "dnsresource_dnsresource_domain_delete_notify",
138+ "dnsresource_dnsresource_domain_insert_notify",
139+ "dnsresource_dnsresource_domain_update_notify",
140+ "dnsresource_ip_addresses_rrset_sipaddress_link_notify",
141+ "dnsresource_ip_addresses_rrset_sipaddress_unlink_notify",
142+ "domain_domain_create_notify",
143+ "domain_domain_delete_notify",
144+ "domain_domain_node_update_notify",
145+ "domain_domain_update_notify",
146+ "event_event_create_machine_device_notify",
147+ "event_event_create_notify",
148+ "fabric_fabric_create_notify",
149+ "fabric_fabric_delete_notify",
150+ "fabric_fabric_machine_update_notify",
151+ "fabric_fabric_update_notify",
152+ "filesystem_nd_filesystem_link_notify",
153+ "filesystem_nd_filesystem_unlink_notify",
154+ "filesystem_nd_filesystem_update_notify",
155+ "filesystemgroup_nd_filesystemgroup_link_notify",
156+ "filesystemgroup_nd_filesystemgroup_unlink_notify",
157+ "filesystemgroup_nd_filesystemgroup_update_notify",
158+ "interface_ip_addresses_nd_sipaddress_dns_link_notify",
159+ "interface_ip_addresses_nd_sipaddress_dns_unlink_notify",
160+ "interface_ip_addresses_nd_sipaddress_link_notify",
161+ "interface_ip_addresses_nd_sipaddress_unlink_notify",
162+ "interface_nd_interface_link_notify",
163+ "interface_nd_interface_unlink_notify",
164+ "interface_nd_interface_update_notify",
165+ "iprange_iprange_create_notify",
166+ "iprange_iprange_delete_notify",
167+ "iprange_iprange_subnet_delete_notify",
168+ "iprange_iprange_subnet_insert_notify",
169+ "iprange_iprange_subnet_update_notify",
170+ "iprange_iprange_update_notify",
171+ "metadataserver_noderesult_nd_noderesult_link_notify",
172+ "metadataserver_noderesult_nd_noderesult_unlink_notify",
173+ "neighbour_neighbour_create_notify",
174+ "neighbour_neighbour_delete_notify",
175+ "neighbour_neighbour_update_notify",
176+ "node_device_create_notify",
177+ "node_device_delete_notify",
178+ "node_device_update_notify",
179+ "node_machine_create_notify",
180+ "node_machine_delete_notify",
181+ "node_machine_update_notify",
182+ "node_node_type_change_notify",
183+ "node_rack_controller_create_notify",
184+ "node_rack_controller_delete_notify",
185+ "node_rack_controller_update_notify",
186+ "node_region_and_rack_controller_create_notify",
187+ "node_region_and_rack_controller_delete_notify",
188+ "node_region_and_rack_controller_update_notify",
189+ "node_region_controller_create_notify",
190+ "node_region_controller_delete_notify",
191+ "node_region_controller_update_notify",
192+ "node_tags_machine_device_tag_link_notify",
193+ "node_tags_machine_device_tag_unlink_notify",
194+ "packagerepository_packagerepository_create_notify",
195+ "packagerepository_packagerepository_delete_notify",
196+ "packagerepository_packagerepository_update_notify",
197+ "partition_nd_partition_link_notify",
198+ "partition_nd_partition_unlink_notify",
199+ "partition_nd_partition_update_notify",
200+ "partitiontable_nd_partitiontable_link_notify",
201+ "partitiontable_nd_partitiontable_unlink_notify",
202+ "partitiontable_nd_partitiontable_update_notify",
203+ "physicalblockdevice_nd_physblockdevice_update_notify",
204+ "service_service_create_notify",
205+ "service_service_delete_notify",
206+ "service_service_update_notify",
207+ "space_space_create_notify",
208+ "space_space_delete_notify",
209+ "space_space_machine_update_notify",
210+ "space_space_update_notify",
211+ "sshkey_sshkey_create_notify",
212+ "sshkey_sshkey_delete_notify",
213+ "sshkey_sshkey_update_notify",
214+ "sshkey_user_sshkey_link_notify",
215+ "sshkey_user_sshkey_unlink_notify",
216+ "sslkey_user_sslkey_link_notify",
217+ "sslkey_user_sslkey_unlink_notify",
218+ "staticipaddress_ipaddress_domain_delete_notify",
219+ "staticipaddress_ipaddress_domain_insert_notify",
220+ "staticipaddress_ipaddress_domain_update_notify",
221+ "staticipaddress_ipaddress_machine_update_notify",
222+ "staticipaddress_ipaddress_subnet_update_notify",
223+ "staticroute_staticroute_create_notify",
224+ "staticroute_staticroute_delete_notify",
225+ "staticroute_staticroute_update_notify",
226+ "subnet_subnet_create_notify",
227+ "subnet_subnet_delete_notify",
228+ "subnet_subnet_machine_update_notify",
229+ "subnet_subnet_update_notify",
230+ "tag_tag_create_notify",
231+ "tag_tag_delete_notify",
232+ "tag_tag_update_machine_device_notify",
233+ "tag_tag_update_notify",
234+ "virtualblockdevice_nd_virtblockdevice_update_notify",
235+ "vlan_vlan_create_notify",
236+ "vlan_vlan_delete_notify",
237+ "vlan_vlan_machine_update_notify",
238+ "vlan_vlan_update_notify",
239+ "zone_zone_create_notify",
240+ "zone_zone_delete_notify",
241+ "zone_zone_update_notify",
242+ }
243+
244+ triggers_all = triggers_system | triggers_websocket
245+
246+ def find_triggers_in_database(self):
247+ with connection.cursor() as cursor:
248+ cursor.execute(
249+ "SELECT tgname::text FROM pg_trigger "
250+ "WHERE NOT tgisinternal")
251+ return {tgname for tgname, in cursor.fetchall()}
252+
253+ def check_triggers_in_database(self):
254+ # Note: if this test fails, a trigger may have been added, but not
255+ # added to the list of expected triggers.
256+ triggers_found = self.find_triggers_in_database()
257+ self.expectThat(
258+ (self.triggers_all - triggers_found), Equals(EMPTY_SET),
259+ "Some triggers were expected but not found.")
260+ self.expectThat(
261+ (triggers_found - self.triggers_all), Equals(EMPTY_SET),
262+ "Some triggers were unexpected.")
263+
264+ def test_all_triggers_present_and_correct(self):
265+ # Running in a fully migrated database means all triggers should be
266+ # present from the get go.
267+ self.check_triggers_in_database()
268+
269+ def test_register_system_triggers_does_not_introduce_more(self):
270+ register_system_triggers()
271+ self.check_triggers_in_database()
272+
273+ def test_register_websocket_triggers_does_not_introduce_more(self):
274+ register_websocket_triggers()
275+ self.check_triggers_in_database()
276
277=== removed file 'src/maasserver/triggers/tests/test_websocket.py'
278--- src/maasserver/triggers/tests/test_websocket.py 2016-10-20 20:56:24 +0000
279+++ src/maasserver/triggers/tests/test_websocket.py 1970-01-01 00:00:00 +0000
280@@ -1,127 +0,0 @@
281-# Copyright 2015-2016 Canonical Ltd. This software is licensed under the
282-# GNU Affero General Public License version 3 (see the file LICENSE).
283-
284-"""Tests for `maasserver.triggers.websocket`."""
285-
286-__all__ = []
287-
288-from contextlib import closing
289-
290-from django.db import connection
291-from maasserver.testing.testcase import MAASServerTestCase
292-from maasserver.triggers.websocket import register_websocket_triggers
293-from maasserver.utils.orm import psql_array
294-
295-
296-class TestTriggers(MAASServerTestCase):
297-
298- def test_register_websocket_triggers(self):
299- register_websocket_triggers()
300- triggers = [
301- "node_machine_create_notify",
302- "node_machine_update_notify",
303- "node_machine_delete_notify",
304- "node_device_create_notify",
305- "node_device_update_notify",
306- "node_device_delete_notify",
307- "config_config_create_notify",
308- "config_config_update_notify",
309- "config_config_delete_notify",
310- "node_rack_controller_create_notify",
311- "node_rack_controller_update_notify",
312- "node_rack_controller_delete_notify",
313- "node_region_controller_create_notify",
314- "node_region_controller_update_notify",
315- "node_region_controller_delete_notify",
316- "node_region_and_rack_controller_create_notify",
317- "node_region_and_rack_controller_update_notify",
318- "node_region_and_rack_controller_delete_notify",
319- "zone_zone_create_notify",
320- "zone_zone_update_notify",
321- "zone_zone_delete_notify",
322- "tag_tag_create_notify",
323- "tag_tag_update_notify",
324- "tag_tag_delete_notify",
325- "node_tags_machine_device_tag_link_notify",
326- "node_tags_machine_device_tag_unlink_notify",
327- "tag_tag_update_machine_device_notify",
328- "auth_user_user_create_notify",
329- "auth_user_user_update_notify",
330- "auth_user_user_delete_notify",
331- "event_event_create_notify",
332- "event_event_create_machine_device_notify",
333- "interface_ip_addresses_nd_sipaddress_link_notify",
334- "interface_ip_addresses_nd_sipaddress_unlink_notify",
335- "interface_ip_addresses_nd_sipaddress_dns_link_notify",
336- "interface_ip_addresses_nd_sipaddress_dns_unlink_notify",
337- "dnsresource_ip_addresses_rrset_sipaddress_link_notify",
338- "dnsresource_ip_addresses_rrset_sipaddress_unlink_notify",
339- "metadataserver_noderesult_nd_noderesult_link_notify",
340- "metadataserver_noderesult_nd_noderesult_unlink_notify",
341- "interface_nd_interface_link_notify",
342- "interface_nd_interface_unlink_notify",
343- "interface_nd_interface_update_notify",
344- "blockdevice_nd_blockdevice_link_notify",
345- "blockdevice_nd_blockdevice_unlink_notify",
346- "physicalblockdevice_nd_physblockdevice_update_notify",
347- "virtualblockdevice_nd_virtblockdevice_update_notify",
348- "sshkey_user_sshkey_link_notify",
349- "sshkey_user_sshkey_unlink_notify",
350- "sshkey_sshkey_create_notify",
351- "sshkey_sshkey_update_notify",
352- "sshkey_sshkey_delete_notify",
353- "sslkey_user_sslkey_link_notify",
354- "sslkey_user_sslkey_unlink_notify",
355- "fabric_fabric_create_notify",
356- "fabric_fabric_update_notify",
357- "fabric_fabric_delete_notify",
358- "vlan_vlan_create_notify",
359- "vlan_vlan_update_notify",
360- "vlan_vlan_delete_notify",
361- "neighbour_neighbour_create_notify",
362- "neighbour_neighbour_update_notify",
363- "neighbour_neighbour_delete_notify",
364- "iprange_iprange_create_notify",
365- "iprange_iprange_update_notify",
366- "iprange_iprange_delete_notify",
367- "staticroute_staticroute_create_notify",
368- "staticroute_staticroute_update_notify",
369- "staticroute_staticroute_delete_notify",
370- "subnet_subnet_create_notify",
371- "subnet_subnet_update_notify",
372- "subnet_subnet_delete_notify",
373- "space_space_create_notify",
374- "space_space_update_notify",
375- "space_space_delete_notify",
376- "subnet_subnet_machine_update_notify",
377- "fabric_fabric_machine_update_notify",
378- "space_space_machine_update_notify",
379- "vlan_vlan_machine_update_notify",
380- "staticipaddress_ipaddress_machine_update_notify",
381- "staticipaddress_ipaddress_subnet_update_notify",
382- "dhcpsnippet_dhcpsnippet_create_notify",
383- "dhcpsnippet_dhcpsnippet_update_notify",
384- "dhcpsnippet_dhcpsnippet_delete_notify",
385- "iprange_iprange_subnet_insert_notify",
386- "iprange_iprange_subnet_update_notify",
387- "iprange_iprange_subnet_delete_notify",
388- ]
389- sql, args = psql_array(triggers, sql_type="text")
390- with closing(connection.cursor()) as cursor:
391- cursor.execute(
392- "SELECT tgname::text FROM pg_trigger WHERE "
393- "tgname::text = ANY(%s) " % sql, args)
394- db_triggers = cursor.fetchall()
395-
396- # Note: if this test fails, a trigger may have been added, but not
397- # added to the list of expected triggers.
398- triggers_found = [trigger[0] for trigger in db_triggers]
399- self.assertEqual(
400- len(triggers), len(db_triggers),
401- "Missing %s triggers in the database. Triggers found: %s" % (
402- len(triggers) - len(db_triggers), triggers_found))
403-
404- self.assertItemsEqual(
405- triggers, triggers_found,
406- "Missing triggers in the database. Triggers found: %s" % (
407- triggers_found))