Merge lp:~maas-maintainers/maas/maas-ha into lp:~maas-committers/maas/trunk

Proposed by Blake Rouse
Status: Merged
Approved by: Blake Rouse
Approved revision: no longer in the source branch.
Merged at revision: 4570
Proposed branch: lp:~maas-maintainers/maas/maas-ha
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 2841 lines (+582/-382)
37 files modified
src/maasserver/api/interfaces.py (+8/-7)
src/maasserver/api/nodes.py (+0/-6)
src/maasserver/api/tests/test_devices.py (+45/-45)
src/maasserver/api/tests/test_events.py (+5/-2)
src/maasserver/api/tests/test_interfaces.py (+20/-17)
src/maasserver/api/tests/test_node.py (+11/-10)
src/maasserver/api/tests/test_nodes.py (+7/-12)
src/maasserver/enum.py (+15/-0)
src/maasserver/fixtures/dev_fixture.yaml (+11/-11)
src/maasserver/forms.py (+2/-1)
src/maasserver/migrations/builtin/maasserver/0003_add_node_type_to_node.py (+22/-0)
src/maasserver/migrations/builtin/maasserver/0004_migrate_installable_to_node_type.py (+29/-0)
src/maasserver/migrations/builtin/maasserver/0005_delete_installable_from_node.py (+21/-0)
src/maasserver/models/__init__.py (+5/-2)
src/maasserver/models/interface.py (+4/-3)
src/maasserver/models/node.py (+30/-16)
src/maasserver/models/signals/power.py (+0/-5)
src/maasserver/models/staticipaddress.py (+1/-1)
src/maasserver/models/tests/test_node.py (+58/-21)
src/maasserver/models/tests/test_staticipaddress.py (+1/-1)
src/maasserver/models/tests/test_zone.py (+37/-12)
src/maasserver/models/zone.py (+10/-4)
src/maasserver/node_action.py (+28/-27)
src/maasserver/rpc/nodes.py (+0/-2)
src/maasserver/rpc/tests/test_nodes.py (+4/-4)
src/maasserver/static/partials/subnet-details.html (+9/-2)
src/maasserver/testing/factory.py (+19/-10)
src/maasserver/tests/test_auth.py (+4/-4)
src/maasserver/tests/test_listener.py (+23/-22)
src/maasserver/tests/test_node_action.py (+13/-12)
src/maasserver/triggers.py (+115/-103)
src/maasserver/websockets/handlers/device.py (+3/-2)
src/maasserver/websockets/handlers/general.py (+4/-4)
src/maasserver/websockets/handlers/node.py (+5/-5)
src/maasserver/websockets/handlers/tests/test_device.py (+4/-2)
src/maasserver/websockets/handlers/tests/test_general.py (+3/-3)
src/maasserver/websockets/handlers/tests/test_node.py (+6/-4)
To merge this branch: bzr merge lp:~maas-maintainers/maas/maas-ha
Reviewer Review Type Date Requested Status
Blake Rouse (community) Approve
Review via email: mp+280969@code.launchpad.net

Commit message

Merge the HA integration branch.

Description of the change

Now that 1.10 has been split this can be merged into trunk.

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

All branches merged in maas-ha have already been reviewed and approved.

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

The attempt to merge lp:~maas-maintainers/maas/maas-ha 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-1.clouds.archive.ubuntu.com/ubuntu xenial InRelease [227 kB]
Hit:3 http://ppa.launchpad.net/maas-maintainers/experimental3/ubuntu xenial InRelease
Hit:4 http://prodstack-zone-1.clouds.archive.ubuntu.com/ubuntu xenial-updates InRelease
Hit:5 http://prodstack-zone-1.clouds.archive.ubuntu.com/ubuntu xenial-backports InRelease
Get:6 http://prodstack-zone-1.clouds.archive.ubuntu.com/ubuntu xenial/main Sources [1,122 kB]
Get:7 http://prodstack-zone-1.clouds.archive.ubuntu.com/ubuntu xenial/universe Sources [7,528 kB]
Get:8 http://prodstack-zone-1.clouds.archive.ubuntu.com/ubuntu xenial/main amd64 Packages [1,463 kB]
Get:9 http://prodstack-zone-1.clouds.archive.ubuntu.com/ubuntu xenial/universe amd64 Packages [7,077 kB]
Get:10 http://prodstack-zone-1.clouds.archive.ubuntu.com/ubuntu xenial/universe Translation-en [4,744 kB]
Fetched 22.2 MB in 9s (2,321 kB/s)
Reading package lists...
Reading package lists...
Building dependency tree...
Reading state information...
Calculating upgrade...
The following packages were automatically installed and are no longer required:
  libc-ares-dev libc-ares2 libisl13 libv8-3.14-dev libv8-3.14.5
  linux-headers-4.3.0-1 linux-headers-4.3.0-1-generic
  linux-image-4.2.0-18-generic linux-image-4.3.0-1-generic
  linux-image-extra-4.3.0-1-generic python-twisted-lore
Use 'sudo apt autoremove' to remove them.
The following packages will be upgraded:
  libgtk2.0-0 libgtk2.0-common
2 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 1,896 kB of archives.
After this operation, 0 B of additional disk space will be used.
Get:1 http://prodstack-zone-1.clouds.archive.ubuntu.com/ubuntu xenial/main amd64 libgtk2.0-common all 2.24.29-1ubuntu1 [122 kB]
Get:2 http://prodstack-zone-1.clouds.archive.ubuntu.com/ubuntu xenial/main amd64 libgtk2.0-0 amd64 2.24.29-1ubuntu1 [1,774 kB]
Fetched 1,896 kB in 0s (8,660 kB/s)
(Reading database ...
(Reading database ... 5%
(Reading database ... 10%
(Reading database ... 15%
(Reading database ... 20%
(Reading database ... 25%
(Reading database ... 30%
(Reading database ... 35%
(Reading database ... 40%
(Reading database ... 45%
(Reading database ... 50%
(Reading database ... 55%
(Reading database ... 60%
(Reading database ... 65%
(Reading database ... 70%
(Reading database ... 75%
(Reading database ... 80%
(Reading database ... 85%
(Reading database ... 90%
(Reading database ... 95%
(Reading database ... 100%
(Reading database ... 186568 files and directories currently installed.)
Preparing to unpack .../libgtk2.0-common_2.24.29-1ubuntu1_all.deb ...
Unpacking libgtk2.0-common (2.24.29-1ubuntu1) over (2.24.28-1ubuntu1) ...
Preparing to unpack .../libgtk2.0-0_2.24.29-1ubuntu1_amd64.deb ...
Unpacking libgtk2.0-0:amd64 (2.24.29-1ubuntu1) over (2.24.28-1ubuntu1) ...
Processing triggers for libc-bin (2.21-0ubuntu5) ...
Setting up libgtk2.0-common (2.24.29-1ubuntu1) ...
Setting up libgtk2.0-0:amd64 (2.24.29-1ubuntu1) ...
Processing triggers for libc-bin (2.21-0ubuntu...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/api/interfaces.py'
2--- src/maasserver/api/interfaces.py 2015-12-07 16:37:36 +0000
3+++ src/maasserver/api/interfaces.py 2015-12-18 15:12:10 +0000
4@@ -13,6 +13,7 @@
5 INTERFACE_TYPE,
6 NODE_PERMISSION,
7 NODE_STATUS,
8+ NODE_TYPE,
9 )
10 from maasserver.exceptions import (
11 MAASAPIValidationError,
12@@ -106,8 +107,8 @@
13 """
14 node = Node.objects.get_node_or_404(
15 system_id, request.user, NODE_PERMISSION.EDIT)
16- # Installable nodes require the node needs to be in the correct state.
17- if node.installable:
18+ # machine type nodes require the node needs to be in the correct state.
19+ if node.node_type == NODE_TYPE.MACHINE:
20 raise_error_for_invalid_state_on_allocated_operations(
21 node, request.user, "create")
22 form = PhysicalInterfaceForm(node=node, data=request.data)
23@@ -371,7 +372,7 @@
24 """
25 interface = Interface.objects.get_interface_or_404(
26 system_id, interface_id, request.user, NODE_PERMISSION.EDIT)
27- if interface.get_node().installable:
28+ if interface.get_node().node_type == NODE_TYPE.MACHINE:
29 # This node needs to be in the correct state to modify
30 # the interface.
31 raise_error_for_invalid_state_on_allocated_operations(
32@@ -401,7 +402,7 @@
33 """
34 interface = Interface.objects.get_interface_or_404(
35 system_id, interface_id, request.user, NODE_PERMISSION.EDIT)
36- if interface.get_node().installable:
37+ if interface.get_node().node_type == NODE_TYPE.MACHINE:
38 # This node needs to be in the correct state to modify
39 # the interface.
40 raise_error_for_invalid_state_on_allocated_operations(
41@@ -443,7 +444,7 @@
42 interface = Interface.objects.get_interface_or_404(
43 system_id, interface_id, request.user, NODE_PERMISSION.EDIT)
44 node = interface.get_node()
45- if node.installable:
46+ if node.node_type == NODE_TYPE.MACHINE:
47 # This node needs to be in the correct state to modify
48 # the interface.
49 raise_error_for_invalid_state_on_allocated_operations(
50@@ -474,7 +475,7 @@
51 """
52 interface = Interface.objects.get_interface_or_404(
53 system_id, interface_id, request.user, NODE_PERMISSION.EDIT)
54- if interface.get_node().installable:
55+ if interface.get_node().node_type == NODE_TYPE.MACHINE:
56 # This node needs to be in the correct state to modify
57 # the interface.
58 raise_error_for_invalid_state_on_allocated_operations(
59@@ -501,7 +502,7 @@
60 """
61 interface = Interface.objects.get_interface_or_404(
62 system_id, interface_id, request.user, NODE_PERMISSION.EDIT)
63- if interface.get_node().installable:
64+ if interface.get_node().node_type == NODE_TYPE.MACHINE:
65 # This node needs to be in the correct state to modify
66 # the interface.
67 raise_error_for_invalid_state_on_allocated_operations(
68
69=== modified file 'src/maasserver/api/nodes.py'
70--- src/maasserver/api/nodes.py 2015-12-05 17:02:05 +0000
71+++ src/maasserver/api/nodes.py 2015-12-18 15:12:10 +0000
72@@ -761,7 +761,6 @@
73 :return: a dict whose key is "state" with a value of one of
74 'on' or 'off'.
75
76- Returns 400 if the node is not installable.
77 Returns 404 if the node is not found.
78 Returns 503 (with explanatory text) if the power state could not
79 be queried.
80@@ -776,11 +775,6 @@
81 addTask = eventloop.services.getServiceNamed("database-tasks").addTask
82
83 node = get_object_or_404(Node, system_id=system_id)
84- if not node.installable:
85- raise MAASAPIBadRequest(
86- "%s: Unable to query power state; not an installable node" %
87- node.hostname)
88-
89 ng = node.nodegroup
90
91 try:
92
93=== modified file 'src/maasserver/api/tests/test_devices.py'
94--- src/maasserver/api/tests/test_devices.py 2015-12-09 02:02:23 +0000
95+++ src/maasserver/api/tests/test_devices.py 2015-12-18 15:12:10 +0000
96@@ -14,6 +14,7 @@
97 INTERFACE_TYPE,
98 IPADDRESS_TYPE,
99 NODE_STATUS,
100+ NODE_TYPE,
101 NODEGROUP_STATUS,
102 NODEGROUPINTERFACE_MANAGEMENT,
103 )
104@@ -64,10 +65,10 @@
105 device = Node.devices.get(system_id=system_id)
106 self.assertEqual(hostname, device.hostname)
107 self.assertIsNone(device.parent)
108- self.assertFalse(device.installable)
109- self.assertEqual(NodeGroup.objects.ensure_master(), device.nodegroup)
110- self.assertEqual(self.logged_in_user, device.owner)
111- self.assertEqual(
112+ self.assertEquals(device.node_type, NODE_TYPE.DEVICE)
113+ self.assertEquals(NodeGroup.objects.ensure_master(), device.nodegroup)
114+ self.assertEquals(self.logged_in_user, device.owner)
115+ self.assertEquals(
116 macs,
117 {nic.mac_address for nic in device.interface_set.all()})
118
119@@ -90,9 +91,9 @@
120 http.client.OK, response.status_code, response.content)
121 system_id = json_load_bytes(response.content)['system_id']
122 device = Node.devices.get(system_id=system_id)
123- self.assertEqual(hostname, device.hostname)
124- self.assertEqual(parent, device.parent)
125- self.assertFalse(device.installable)
126+ self.assertEquals(hostname, device.hostname)
127+ self.assertEquals(parent, device.parent)
128+ self.assertEqual(device.node_type, NODE_TYPE.DEVICE)
129
130 def test_POST_returns_limited_fields(self):
131 response = self.client.post(
132@@ -120,8 +121,8 @@
133 def create_devices(self, owner, nodegroup=None, nb=3):
134 return [
135 factory.make_Node(
136- nodegroup=nodegroup, interface=True, installable=False,
137- owner=owner)
138+ nodegroup=nodegroup, interface=True,
139+ node_type=NODE_TYPE.DEVICE, owner=owner)
140 for _ in range(nb)
141 ]
142
143@@ -213,7 +214,7 @@
144
145 def test_POST_method_doesnt_exist(self):
146 device = factory.make_Node(
147- installable=False, owner=self.logged_in_user)
148+ node_type=NODE_TYPE.DEVICE, owner=self.logged_in_user)
149
150 response = self.client.post(get_device_uri(device))
151 self.assertEqual(
152@@ -221,7 +222,7 @@
153
154 def test_GET_reads_device(self):
155 device = factory.make_Node(
156- installable=False, owner=self.logged_in_user)
157+ node_type=NODE_TYPE.DEVICE, owner=self.logged_in_user)
158
159 response = self.client.get(get_device_uri(device))
160 self.assertEqual(
161@@ -231,7 +232,7 @@
162
163 def test_PUT_updates_device_hostname(self):
164 device = factory.make_Node(
165- installable=False, owner=self.logged_in_user)
166+ node_type=NODE_TYPE.DEVICE, owner=self.logged_in_user)
167 new_hostname = factory.make_name('hostname')
168
169 response = self.client.put(
170@@ -245,7 +246,8 @@
171 def test_PUT_updates_device_parent(self):
172 parent = factory.make_Node()
173 device = factory.make_Node(
174- installable=False, owner=self.logged_in_user, parent=parent)
175+ node_type=NODE_TYPE.DEVICE, owner=self.logged_in_user,
176+ parent=parent)
177 new_parent = factory.make_Node()
178
179 response = self.client.put(
180@@ -258,7 +260,7 @@
181
182 def test_PUT_rejects_edit_if_not_permitted(self):
183 device = factory.make_Node(
184- installable=False, owner=factory.make_User())
185+ node_type=NODE_TYPE.DEVICE, owner=factory.make_User())
186 old_hostname = device.hostname
187
188 response = self.client.put(
189@@ -269,7 +271,7 @@
190
191 def test_DELETE_removes_device(self):
192 device = factory.make_Node(
193- installable=False, owner=self.logged_in_user)
194+ node_type=NODE_TYPE.DEVICE, owner=self.logged_in_user)
195 response = self.client.delete(get_device_uri(device))
196 self.assertEqual(
197 http.client.NO_CONTENT, response.status_code, response.content)
198@@ -277,7 +279,7 @@
199
200 def test_DELETE_rejects_deletion_if_not_permitted(self):
201 device = factory.make_Node(
202- installable=False, owner=factory.make_User())
203+ node_type=NODE_TYPE.DEVICE, owner=factory.make_User())
204 response = self.client.delete(get_device_uri(device))
205 self.assertEqual(http.client.FORBIDDEN, response.status_code)
206 self.assertEqual(device, reload_object(device))
207@@ -292,9 +294,9 @@
208 ng, management=NODEGROUPINTERFACE_MANAGEMENT.DHCP_AND_DNS)
209 parent = factory.make_Node_with_Interface_on_Subnet(
210 nodegroup=ng, subnet=ngi.subnet)
211- device = factory.make_Node(
212- installable=False, parent=parent, interface=True,
213- disable_ipv4=False, owner=self.logged_in_user)
214+ device = factory.make_Device(
215+ parent=parent, interface=True, disable_ipv4=False,
216+ owner=self.logged_in_user)
217 # Silence 'update_host_maps'.
218 self.patch_autospec(interface_module, "update_host_maps")
219 response = self.client.post(
220@@ -313,9 +315,9 @@
221 ng, management=NODEGROUPINTERFACE_MANAGEMENT.UNMANAGED)
222 parent = factory.make_Node_with_Interface_on_Subnet(
223 nodegroup=ng, subnet=ngi.subnet)
224- device = factory.make_Node(
225- installable=False, parent=parent, interface=True,
226- disable_ipv4=False, owner=self.logged_in_user)
227+ device = factory.make_Device(
228+ parent=parent, interface=True, disable_ipv4=False,
229+ owner=self.logged_in_user)
230 # Silence 'update_host_maps'.
231 self.patch_autospec(interface_module, "update_host_maps")
232 response = self.client.post(
233@@ -337,9 +339,9 @@
234 ngi.save()
235 parent = factory.make_Node_with_Interface_on_Subnet(
236 nodegroup=ng, subnet=subnet, unmanaged=True)
237- device = factory.make_Node(
238- installable=False, parent=parent, interface=True,
239- disable_ipv4=False, owner=self.logged_in_user)
240+ device = factory.make_Device(
241+ parent=parent, interface=True, disable_ipv4=False,
242+ owner=self.logged_in_user)
243 # Silence 'update_host_maps'.
244 self.patch_autospec(interface_module, "update_host_maps")
245 response = self.client.post(
246@@ -384,7 +386,7 @@
247 def test__claims_ip_address_from_cluster_interface(self):
248 parent = factory.make_Node_with_Interface_on_Subnet()
249 device = factory.make_Node(
250- installable=False, parent=parent, interface=True,
251+ node_type=NODE_TYPE.DEVICE, parent=parent, interface=True,
252 disable_ipv4=False, owner=self.logged_in_user)
253 # Silence 'update_host_maps'.
254 self.patch_autospec(interface_module, "update_host_maps")
255@@ -401,7 +403,7 @@
256 def test__rejected_if_not_permitted(self):
257 parent = factory.make_Node_with_Interface_on_Subnet()
258 device = factory.make_Node(
259- installable=False, parent=parent, interface=True,
260+ node_type=NODE_TYPE.DEVICE, parent=parent, interface=True,
261 disable_ipv4=False, owner=factory.make_User())
262 self.patch_autospec(interface_module, "update_host_maps")
263 response = self.client.post(
264@@ -411,7 +413,7 @@
265 def test_creates_ip_with_random_ip(self):
266 requested_address = factory.make_ip_address()
267 device = factory.make_Node(
268- installable=False, interface=True, disable_ipv4=False,
269+ node_type=NODE_TYPE.DEVICE, interface=True, disable_ipv4=False,
270 owner=self.logged_in_user)
271 # Silence 'update_host_maps'.
272 self.patch_autospec(interface_module, "update_host_maps")
273@@ -432,9 +434,8 @@
274 )
275
276 def test_503_if_no_subnet_found(self):
277- device = factory.make_Node(
278- installable=False, interface=True, disable_ipv4=False,
279- owner=self.logged_in_user)
280+ device = factory.make_Device(
281+ interface=True, disable_ipv4=False, owner=self.logged_in_user)
282 # Silence 'update_host_maps'.
283 self.patch_autospec(interface_module, "update_host_maps")
284 response = self.client.post(
285@@ -450,9 +451,8 @@
286 def test_503_if_no_ip_found(self, claim_static_ips):
287 claim_static_ips.side_effect = [list()]
288
289- device = factory.make_Node(
290- installable=False, interface=True, disable_ipv4=False,
291- owner=self.logged_in_user)
292+ device = factory.make_Device(
293+ interface=True, disable_ipv4=False, owner=self.logged_in_user)
294 # Silence 'update_host_maps'.
295 self.patch_autospec(interface_module, "update_host_maps")
296 response = self.client.post(
297@@ -467,7 +467,7 @@
298 def test_creates_ip_for_specific_mac(self):
299 requested_address = factory.make_ip_address()
300 device = factory.make_Node(
301- installable=False, interface=True, disable_ipv4=False,
302+ node_type=NODE_TYPE.DEVICE, interface=True, disable_ipv4=False,
303 owner=self.logged_in_user)
304 second_nic = factory.make_Interface(
305 INTERFACE_TYPE.PHYSICAL, node=device)
306@@ -493,7 +493,7 @@
307 def test_rejects_invalid_ip(self):
308 requested_address = factory.make_name('bogus')
309 device = factory.make_Node(
310- installable=False, interface=True, disable_ipv4=False,
311+ node_type=NODE_TYPE.DEVICE, interface=True, disable_ipv4=False,
312 owner=self.logged_in_user)
313 interface = device.interface_set.all()[0]
314 response = self.client.post(
315@@ -512,7 +512,7 @@
316 mac_address = factory.make_name('bogus')
317 requested_address = factory.make_ip_address()
318 device = factory.make_Node(
319- installable=False, interface=True, disable_ipv4=False,
320+ node_type=NODE_TYPE.DEVICE, interface=True, disable_ipv4=False,
321 owner=self.logged_in_user)
322 response = self.client.post(
323 get_device_uri(device),
324@@ -531,13 +531,13 @@
325 def test_rejects_unrelated_mac(self):
326 # Create an other device.
327 other_device = factory.make_Node(
328- installable=False, interface=True, disable_ipv4=False,
329+ node_type=NODE_TYPE.DEVICE, interface=True, disable_ipv4=False,
330 owner=factory.make_User())
331 other_nic = other_device.interface_set.all()[0]
332
333 requested_address = factory.make_ip_address()
334 device = factory.make_Node(
335- installable=False, interface=True, disable_ipv4=False,
336+ node_type=NODE_TYPE.DEVICE, interface=True, disable_ipv4=False,
337 owner=self.logged_in_user)
338 # Silence 'update_host_maps'.
339 self.patch_autospec(interface_module, "update_host_maps")
340@@ -558,7 +558,7 @@
341 def test__releases_ip_address(self):
342 parent = factory.make_Node_with_Interface_on_Subnet()
343 device = factory.make_Node(
344- installable=False, parent=parent, interface=True,
345+ node_type=NODE_TYPE.DEVICE, parent=parent, interface=True,
346 disable_ipv4=False, owner=self.logged_in_user)
347 # Silence 'update_host_maps' and 'remove_host_maps'
348 self.patch_autospec(interface_module, "update_host_maps")
349@@ -579,7 +579,7 @@
350
351 def test__rejects_invalid_ip(self):
352 device = factory.make_Node(
353- installable=False, interface=True, disable_ipv4=False,
354+ node_type=NODE_TYPE.DEVICE, interface=True, disable_ipv4=False,
355 owner=self.logged_in_user)
356 response = self.client.post(
357 get_device_uri(device),
358@@ -595,7 +595,7 @@
359
360 def test__rejects_empty_ip(self):
361 device = factory.make_Node(
362- installable=False, interface=True, disable_ipv4=False,
363+ node_type=NODE_TYPE.DEVICE, interface=True, disable_ipv4=False,
364 owner=self.logged_in_user)
365 response = self.client.post(
366 get_device_uri(device),
367@@ -616,7 +616,7 @@
368 network = factory._make_random_network(slash=24)
369 subnet = factory.make_Subnet(cidr=str(network.cidr))
370 device = factory.make_Node_with_Interface_on_Subnet(
371- installable=False, subnet=subnet,
372+ node_type=NODE_TYPE.DEVICE, subnet=subnet,
373 disable_ipv4=False, owner=self.logged_in_user)
374 for _ in range(4):
375 extra_nic = factory.make_Interface(
376@@ -643,7 +643,7 @@
377 network = factory._make_random_network(slash=24)
378 subnet = factory.make_Subnet(cidr=str(network.cidr))
379 device = factory.make_Node_with_Interface_on_Subnet(
380- installable=False, subnet=subnet,
381+ node_type=NODE_TYPE.DEVICE, subnet=subnet,
382 disable_ipv4=False, owner=self.logged_in_user)
383 extra_nic = factory.make_Interface(
384 INTERFACE_TYPE.PHYSICAL, node=device)
385@@ -675,7 +675,7 @@
386 def test__rejected_if_not_permitted(self):
387 parent = factory.make_Node_with_Interface_on_Subnet()
388 device = factory.make_Node(
389- installable=False, parent=parent, interface=True,
390+ node_type=NODE_TYPE.DEVICE, parent=parent, interface=True,
391 disable_ipv4=False, owner=factory.make_User())
392 # Silence 'update_host_maps' and 'remove_host_maps'
393 self.patch_autospec(interface_module, "update_host_maps")
394
395=== modified file 'src/maasserver/api/tests/test_events.py'
396--- src/maasserver/api/tests/test_events.py 2015-12-04 08:25:27 +0000
397+++ src/maasserver/api/tests/test_events.py 2015-12-18 15:12:10 +0000
398@@ -19,7 +19,10 @@
399 from django.core.urlresolvers import reverse
400 from maasserver.api import events as events_module
401 from maasserver.api.tests.test_nodes import RequestFixture
402-from maasserver.enum import INTERFACE_TYPE
403+from maasserver.enum import (
404+ INTERFACE_TYPE,
405+ NODE_TYPE,
406+)
407 from maasserver.models.eventtype import LOGGING_LEVELS
408 from maasserver.testing.api import APITestCase
409 from maasserver.testing.factory import factory
410@@ -311,7 +314,7 @@
411
412 # Create devices.
413 device_nodes = [
414- factory.make_Node(installable=False)
415+ factory.make_Node(node_type=NODE_TYPE.DEVICE)
416 for _ in range(3)]
417 [factory.make_Event(node=node) for node in device_nodes]
418
419
420=== modified file 'src/maasserver/api/tests/test_interfaces.py'
421--- src/maasserver/api/tests/test_interfaces.py 2015-12-07 16:37:36 +0000
422+++ src/maasserver/api/tests/test_interfaces.py 2015-12-18 15:12:10 +0000
423@@ -14,6 +14,7 @@
424 INTERFACE_TYPE,
425 IPADDRESS_TYPE,
426 NODE_STATUS,
427+ NODE_TYPE,
428 )
429 from maasserver.models import Interface
430 from maasserver.testing.api import APITestCase
431@@ -93,8 +94,8 @@
432
433 def test_read_on_device(self):
434 parent = factory.make_Node()
435- device = factory.make_Node(
436- owner=self.logged_in_user, installable=False, parent=parent)
437+ device = factory.make_Device(
438+ owner=self.logged_in_user, parent=parent)
439 interface = factory.make_Interface(
440 INTERFACE_TYPE.PHYSICAL, node=device)
441 uri = get_interfaces_uri(device)
442@@ -140,8 +141,8 @@
443
444 def test_create_physical_on_device(self):
445 parent = factory.make_Node()
446- device = factory.make_Node(
447- owner=self.logged_in_user, installable=False, parent=parent)
448+ device = factory.make_Device(
449+ owner=self.logged_in_user, parent=parent)
450 mac = factory.make_mac_address()
451 name = factory.make_name("eth")
452 vlan = factory.make_VLAN()
453@@ -333,7 +334,8 @@
454 def test_create_bond_404_on_device(self):
455 parent = factory.make_Node()
456 device = factory.make_Node(
457- owner=self.logged_in_user, installable=False, parent=parent)
458+ owner=self.logged_in_user, parent=parent,
459+ node_type=NODE_TYPE.DEVICE)
460 uri = get_interfaces_uri(device)
461 response = self.client.post(uri, {
462 "op": "create_bond",
463@@ -448,7 +450,8 @@
464 def test_create_vlan_404_on_device(self):
465 parent = factory.make_Node()
466 device = factory.make_Node(
467- owner=self.logged_in_user, installable=False, parent=parent)
468+ owner=self.logged_in_user, parent=parent,
469+ node_type=NODE_TYPE.DEVICE)
470 uri = get_interfaces_uri(device)
471 response = self.client.post(uri, {
472 "op": "create_vlan",
473@@ -606,7 +609,7 @@
474
475 def test_read_device_interface(self):
476 parent = factory.make_Node()
477- device = factory.make_Node(installable=False, parent=parent)
478+ device = factory.make_Device(parent=parent)
479 interface = factory.make_Interface(
480 INTERFACE_TYPE.PHYSICAL, node=device)
481 uri = get_interface_uri(interface)
482@@ -646,8 +649,8 @@
483
484 def test_update_device_physical_interface(self):
485 node = factory.make_Node()
486- device = factory.make_Node(
487- owner=self.logged_in_user, installable=False, parent=node)
488+ device = factory.make_Device(
489+ owner=self.logged_in_user, parent=node)
490 interface = factory.make_Interface(
491 INTERFACE_TYPE.PHYSICAL, node=device)
492 new_name = factory.make_name("name")
493@@ -749,8 +752,8 @@
494
495 def test_delete_deletes_device_interface(self):
496 parent = factory.make_Node()
497- device = factory.make_Node(
498- owner=self.logged_in_user, installable=False, parent=parent)
499+ device = factory.make_Device(
500+ owner=self.logged_in_user, parent=parent)
501 interface = factory.make_Interface(
502 INTERFACE_TYPE.PHYSICAL, node=device)
503 uri = get_interface_uri(interface)
504@@ -826,8 +829,8 @@
505
506 def test_link_subnet_creates_link_on_device(self):
507 parent = factory.make_Node()
508- device = factory.make_Node(
509- owner=self.logged_in_user, installable=False, parent=parent)
510+ device = factory.make_Device(
511+ owner=self.logged_in_user, parent=parent)
512 interface = factory.make_Interface(
513 INTERFACE_TYPE.PHYSICAL, node=device)
514 subnet = factory.make_Subnet(vlan=interface.vlan)
515@@ -847,8 +850,8 @@
516
517 def test_link_subnet_on_device_only_allows_static(self):
518 parent = factory.make_Node()
519- device = factory.make_Node(
520- owner=self.logged_in_user, installable=False, parent=parent)
521+ device = factory.make_Device(
522+ owner=self.logged_in_user, parent=parent)
523 interface = factory.make_Interface(
524 INTERFACE_TYPE.PHYSICAL, node=device)
525 for link_type in [
526@@ -941,8 +944,8 @@
527
528 def test_unlink_subnet_deletes_link_on_device(self):
529 parent = factory.make_Node()
530- device = factory.make_Node(
531- owner=self.logged_in_user, installable=False, parent=parent)
532+ device = factory.make_Device(
533+ owner=self.logged_in_user, parent=parent)
534 interface = factory.make_Interface(
535 INTERFACE_TYPE.PHYSICAL, node=device)
536 subnet = factory.make_Subnet()
537
538=== modified file 'src/maasserver/api/tests/test_node.py'
539--- src/maasserver/api/tests/test_node.py 2015-12-04 11:46:07 +0000
540+++ src/maasserver/api/tests/test_node.py 2015-12-18 15:12:10 +0000
541@@ -23,6 +23,7 @@
542 NODE_STATUS,
543 NODE_STATUS_CHOICES,
544 NODE_STATUS_CHOICES_DICT,
545+ NODE_TYPE,
546 POWER_STATE,
547 )
548 from maasserver.fields import (
549@@ -299,7 +300,7 @@
550
551 def test_GET_rejects_device(self):
552 node = factory.make_Node(
553- installable=False, owner=self.logged_in_user)
554+ node_type=NODE_TYPE.DEVICE, owner=self.logged_in_user)
555 response = self.client.get(self.get_node_uri(node))
556 self.assertEqual(
557 http.client.NOT_FOUND, response.status_code, response.content)
558@@ -352,7 +353,7 @@
559
560 def test_POST_stop_rejects_device(self):
561 node = factory.make_Node(
562- installable=False, owner=self.logged_in_user)
563+ node_type=NODE_TYPE.DEVICE, owner=self.logged_in_user)
564 response = self.client.post(self.get_node_uri(node), {'op': 'stop'})
565 self.assertEqual(
566 http.client.NOT_FOUND, response.status_code, response.content)
567@@ -455,7 +456,7 @@
568
569 def test_POST_start_rejects_device(self):
570 node = factory.make_Node(
571- installable=False, owner=self.logged_in_user)
572+ node_type=NODE_TYPE.DEVICE, owner=self.logged_in_user)
573 response = self.client.post(self.get_node_uri(node), {'op': 'start'})
574 self.assertEqual(
575 http.client.NOT_FOUND, response.status_code, response.content)
576@@ -724,7 +725,7 @@
577
578 def test_POST_release_rejects_device(self):
579 node = factory.make_Node(
580- installable=False, owner=self.logged_in_user)
581+ node_type=NODE_TYPE.DEVICE, owner=self.logged_in_user)
582 response = self.client.post(self.get_node_uri(node), {'op': 'release'})
583 self.assertEqual(
584 http.client.NOT_FOUND, response.status_code, response.content)
585@@ -931,7 +932,7 @@
586 def test_PUT_rejects_device(self):
587 self.become_admin()
588 node = factory.make_Node(
589- installable=False, owner=self.logged_in_user)
590+ node_type=NODE_TYPE.DEVICE, owner=self.logged_in_user)
591 response = self.client.put(self.get_node_uri(node))
592 self.assertEqual(
593 http.client.NOT_FOUND, response.status_code, response.content)
594@@ -1389,7 +1390,7 @@
595
596 def test_DELETE_rejects_device(self):
597 node = factory.make_Node(
598- installable=False, owner=self.logged_in_user)
599+ node_type=NODE_TYPE.DEVICE, owner=self.logged_in_user)
600 response = self.client.delete(self.get_node_uri(node))
601 self.assertEqual(
602 http.client.NOT_FOUND, response.status_code, response.content)
603@@ -1717,8 +1718,8 @@
604 network = factory._make_random_network(slash=24)
605 subnet = factory.make_Subnet(cidr=str(network.cidr))
606 node = factory.make_Node_with_Interface_on_Subnet(
607- status=NODE_STATUS.ALLOCATED, installable=True, subnet=subnet,
608- disable_ipv4=False, owner=self.logged_in_user)
609+ status=NODE_STATUS.ALLOCATED, node_type=NODE_TYPE.MACHINE,
610+ subnet=subnet, disable_ipv4=False, owner=self.logged_in_user)
611 boot_interface = node.get_boot_interface()
612 # Silence 'update_host_maps' and 'remove_host_maps'
613 self.patch(interface_module, "update_host_maps")
614@@ -1739,8 +1740,8 @@
615 network = factory._make_random_network(slash=24)
616 subnet = factory.make_Subnet(cidr=str(network.cidr))
617 node = factory.make_Node_with_Interface_on_Subnet(
618- status=NODE_STATUS.ALLOCATED, installable=True, subnet=subnet,
619- disable_ipv4=False, owner=self.logged_in_user)
620+ status=NODE_STATUS.ALLOCATED, node_type=NODE_TYPE.MACHINE,
621+ subnet=subnet, disable_ipv4=False, owner=self.logged_in_user)
622 boot_interface = node.get_boot_interface()
623 # Silence 'update_host_maps' and 'remove_host_maps'
624 self.patch(interface_module, "update_host_maps")
625
626=== modified file 'src/maasserver/api/tests/test_nodes.py'
627--- src/maasserver/api/tests/test_nodes.py 2015-12-04 08:25:27 +0000
628+++ src/maasserver/api/tests/test_nodes.py 2015-12-18 15:12:10 +0000
629@@ -24,6 +24,7 @@
630 INTERFACE_TYPE,
631 NODE_STATUS,
632 NODE_STATUS_CHOICES_DICT,
633+ NODE_TYPE,
634 NODEGROUP_STATUS,
635 NODEGROUPINTERFACE_MANAGEMENT,
636 POWER_STATE,
637@@ -329,7 +330,7 @@
638 for _ in range(3)]
639 # Create devices.
640 nodes = [
641- factory.make_Node(installable=False)
642+ factory.make_Node(node_type=NODE_TYPE.DEVICE)
643 for _ in range(3)]
644
645 query = RequestFixture({}, '')
646@@ -690,7 +691,7 @@
647 for _ in range(3)]
648 # Create devices.
649 nodes = [
650- factory.make_Node(installable=False)
651+ factory.make_Node(node_type=NODE_TYPE.DEVICE)
652 for _ in range(3)]
653 response = self.client.get(reverse('nodes_handler'), {'op': 'list'})
654 self.assertEqual(http.client.OK, response.status_code)
655@@ -1548,7 +1549,7 @@
656
657 def test_POST_accept_fails_for_device(self):
658 self.become_admin()
659- factory.make_Node(installable=False)
660+ factory.make_Node(node_type=NODE_TYPE.DEVICE)
661 node_id = factory.make_string()
662 response = self.client.post(
663 reverse('nodes_handler'), {'op': 'accept', 'nodes': [node_id]})
664@@ -1610,7 +1611,7 @@
665
666 def test_POST_release_ignores_devices(self):
667 node_ids = {
668- factory.make_Node(installable=False).system_id
669+ factory.make_Node(node_type=NODE_TYPE.DEVICE).system_id
670 for _ in range(3)
671 }
672 response = self.client.post(
673@@ -1922,7 +1923,7 @@
674
675 def test_GET_rejects_devices(self):
676 owned_node = factory.make_Node(
677- installable=False, owner=self.logged_in_user)
678+ node_type=NODE_TYPE.DEVICE, owner=self.logged_in_user)
679 response = self.client.get(
680 self.endpoint,
681 {'op': 'deployment_status', 'nodes': [owned_node.system_id]})
682@@ -2094,7 +2095,7 @@
683 def test__catches_no_connection_error(self):
684 getClientFor = self.patch(nodes_module, 'getClientFor')
685 getClientFor.side_effect = NoConnectionsAvailable()
686- node = factory.make_Node(power_state=POWER_STATE.ON)
687+ node = factory.make_Node(power_state=POWER_STATE.ON, power_type=None)
688
689 response = self.client.get(
690 self.get_node_uri(node), {"op": "query_power_state"})
691@@ -2167,12 +2168,6 @@
692 # The node's power state is now "unknown".
693 self.assertPowerState(node, POWER_STATE.UNKNOWN)
694
695- def test__returns_400_if_device(self):
696- device = factory.make_Device()
697- response = self.client.get(
698- self.get_node_uri(device), {"op": "query_power_state"})
699- self.assertResponseCode(http.client.BAD_REQUEST, response)
700-
701 def test__returns_actual_state(self):
702 node = factory.make_Node(power_type="ipmi")
703 random_state = random.choice(["on", "off", "error"])
704
705=== modified file 'src/maasserver/enum.py'
706--- src/maasserver/enum.py 2015-12-01 18:12:59 +0000
707+++ src/maasserver/enum.py 2015-12-18 15:12:10 +0000
708@@ -127,6 +127,21 @@
709 ]
710
711
712+class NODE_TYPE:
713+ """ Valid node types."""
714+ DEFAULT = 0
715+ MACHINE = 0
716+ DEVICE = 1
717+ RACK_CONTROLLER = 2
718+
719+
720+NODE_TYPE_CHOICES = (
721+ (NODE_TYPE.MACHINE, "Machine"),
722+ (NODE_TYPE.DEVICE, "Device"),
723+ (NODE_TYPE.RACK_CONTROLLER, "Rack controller"),
724+)
725+
726+
727 class NODE_PERMISSION:
728 """Permissions relating to nodes."""
729 VIEW = 'view_node'
730
731=== modified file 'src/maasserver/fixtures/dev_fixture.yaml'
732--- src/maasserver/fixtures/dev_fixture.yaml 2015-12-17 09:32:42 +0000
733+++ src/maasserver/fixtures/dev_fixture.yaml 2015-12-18 15:12:10 +0000
734@@ -1248,7 +1248,7 @@
735 gateway_link_ipv6: null
736 hostname: mild-chicken
737 hwe_kernel: ''
738- installable: true
739+ node_type: 0
740 license_key: ''
741 memory: 1024
742 min_hwe_kernel: ''
743@@ -1290,7 +1290,7 @@
744 gateway_link_ipv6: null
745 hostname: powerless-slip
746 hwe_kernel: hwe-t
747- installable: true
748+ node_type: 0
749 license_key: ''
750 memory: 1024
751 min_hwe_kernel: ''
752@@ -1332,7 +1332,7 @@
753 gateway_link_ipv6: null
754 hostname: frightening-visitor
755 hwe_kernel: ''
756- installable: true
757+ node_type: 0
758 license_key: ''
759 memory: 1024
760 min_hwe_kernel: ''
761@@ -1374,7 +1374,7 @@
762 gateway_link_ipv6: null
763 hostname: lanky-chickens
764 hwe_kernel: ''
765- installable: true
766+ node_type: 0
767 license_key: ''
768 memory: 1024
769 min_hwe_kernel: ''
770@@ -1416,7 +1416,7 @@
771 gateway_link_ipv6: null
772 hostname: squiggly-bomb
773 hwe_kernel: ''
774- installable: true
775+ node_type: 0
776 license_key: ''
777 memory: 1024
778 min_hwe_kernel: ''
779@@ -1458,7 +1458,7 @@
780 gateway_link_ipv6: null
781 hostname: definite-worm
782 hwe_kernel: hwe-t
783- installable: true
784+ node_type: 0
785 license_key: ''
786 memory: 1024
787 min_hwe_kernel: ''
788@@ -1500,7 +1500,7 @@
789 gateway_link_ipv6: null
790 hostname: variable-brush
791 hwe_kernel: ''
792- installable: true
793+ node_type: 0
794 license_key: ''
795 memory: 1024
796 min_hwe_kernel: ''
797@@ -1542,7 +1542,7 @@
798 gateway_link_ipv6: null
799 hostname: urban-railway
800 hwe_kernel: ''
801- installable: true
802+ node_type: 0
803 license_key: ''
804 memory: 1024
805 min_hwe_kernel: ''
806@@ -1584,7 +1584,7 @@
807 gateway_link_ipv6: null
808 hostname: test-device
809 hwe_kernel: null
810- installable: false
811+ node_type: 1
812 license_key: null
813 memory: 0
814 min_hwe_kernel: null
815@@ -1626,7 +1626,7 @@
816 gateway_link_ipv6: null
817 hostname: test2-device
818 hwe_kernel: null
819- installable: false
820+ node_type: 1
821 license_key: null
822 memory: 0
823 min_hwe_kernel: null
824@@ -1666,7 +1666,7 @@
825 gateway_link_ipv6: null
826 hostname: test3-device
827 hwe_kernel: null
828- installable: false
829+ node_type: 1
830 license_key: null
831 memory: 0
832 min_hwe_kernel: null
833
834=== modified file 'src/maasserver/forms.py'
835--- src/maasserver/forms.py 2015-12-01 18:12:59 +0000
836+++ src/maasserver/forms.py 2015-12-18 15:12:10 +0000
837@@ -86,6 +86,7 @@
838 NODE_BOOT,
839 NODE_BOOT_CHOICES,
840 NODE_STATUS,
841+ NODE_TYPE,
842 NODEGROUPINTERFACE_MANAGEMENT,
843 NODEGROUPINTERFACE_MANAGEMENT_CHOICES,
844 )
845@@ -775,7 +776,7 @@
846
847 def save(self, commit=True):
848 device = super(DeviceForm, self).save(commit=False)
849- device.installable = False
850+ device.node_type = NODE_TYPE.DEVICE
851 if self.new_device:
852 # Set the owner: devices are owned by their creator.
853 device.owner = self.request.user
854
855=== added file 'src/maasserver/migrations/builtin/maasserver/0003_add_node_type_to_node.py'
856--- src/maasserver/migrations/builtin/maasserver/0003_add_node_type_to_node.py 1970-01-01 00:00:00 +0000
857+++ src/maasserver/migrations/builtin/maasserver/0003_add_node_type_to_node.py 2015-12-18 15:12:10 +0000
858@@ -0,0 +1,22 @@
859+# -*- coding: utf-8 -*-
860+from __future__ import unicode_literals
861+
862+from django.db import (
863+ migrations,
864+ models,
865+)
866+
867+
868+class Migration(migrations.Migration):
869+
870+ dependencies = [
871+ ('maasserver', '0002_remove_candidate_name_model'),
872+ ]
873+
874+ operations = [
875+ migrations.AddField(
876+ model_name='node',
877+ name='node_type',
878+ field=models.IntegerField(default=0, editable=False, choices=[(0, 'Machine'), (1, 'Device'), (2, 'Rack controller')]),
879+ ),
880+ ]
881
882=== added file 'src/maasserver/migrations/builtin/maasserver/0004_migrate_installable_to_node_type.py'
883--- src/maasserver/migrations/builtin/maasserver/0004_migrate_installable_to_node_type.py 1970-01-01 00:00:00 +0000
884+++ src/maasserver/migrations/builtin/maasserver/0004_migrate_installable_to_node_type.py 2015-12-18 15:12:10 +0000
885@@ -0,0 +1,29 @@
886+# -*- coding: utf-8 -*-
887+from __future__ import unicode_literals
888+
889+from django.db import (
890+ migrations,
891+ models,
892+)
893+from maasserver.enum import NODE_TYPE
894+
895+
896+def convert_installable_to_node_type(apps, schema_editor):
897+ Node = apps.get_model("maasserver", "Node")
898+ for node in Node.objects.all():
899+ if node.installable:
900+ node.node_type = NODE_TYPE.MACHINE
901+ else:
902+ node.node_type = NODE_TYPE.DEVICE
903+ node.save(update_fields=['node_type'])
904+
905+
906+class Migration(migrations.Migration):
907+
908+ dependencies = [
909+ ('maasserver', '0003_add_node_type_to_node'),
910+ ]
911+
912+ operations = [
913+ migrations.RunPython(convert_installable_to_node_type),
914+ ]
915
916=== added file 'src/maasserver/migrations/builtin/maasserver/0005_delete_installable_from_node.py'
917--- src/maasserver/migrations/builtin/maasserver/0005_delete_installable_from_node.py 1970-01-01 00:00:00 +0000
918+++ src/maasserver/migrations/builtin/maasserver/0005_delete_installable_from_node.py 2015-12-18 15:12:10 +0000
919@@ -0,0 +1,21 @@
920+# -*- coding: utf-8 -*-
921+from __future__ import unicode_literals
922+
923+from django.db import (
924+ migrations,
925+ models,
926+)
927+
928+
929+class Migration(migrations.Migration):
930+
931+ dependencies = [
932+ ('maasserver', '0004_migrate_installable_to_node_type'),
933+ ]
934+
935+ operations = [
936+ migrations.RemoveField(
937+ model_name='node',
938+ name='installable',
939+ ),
940+ ]
941
942=== modified file 'src/maasserver/models/__init__.py'
943--- src/maasserver/models/__init__.py 2015-12-07 16:37:36 +0000
944+++ src/maasserver/models/__init__.py 2015-12-18 15:12:10 +0000
945@@ -56,7 +56,10 @@
946 )
947 from django.db.models.signals import post_save
948 from maasserver import logger
949-from maasserver.enum import NODE_PERMISSION
950+from maasserver.enum import (
951+ NODE_PERMISSION,
952+ NODE_TYPE,
953+)
954 from maasserver.models.blockdevice import BlockDevice
955 from maasserver.models.bootresource import BootResource
956 from maasserver.models.bootresourcefile import BootResourceFile
957@@ -260,7 +263,7 @@
958 elif perm in NODE_PERMISSION.EDIT:
959 # A device can be editted by its owner a node must be admin.
960 node = obj.get_node()
961- if node is None or node.installable:
962+ if node is None or node.node_type == NODE_TYPE.MACHINE:
963 return user.is_superuser
964 else:
965 return node.owner == user
966
967=== modified file 'src/maasserver/models/interface.py'
968--- src/maasserver/models/interface.py 2015-12-11 01:48:39 +0000
969+++ src/maasserver/models/interface.py 2015-12-18 15:12:10 +0000
970@@ -40,6 +40,7 @@
971 INTERFACE_TYPE,
972 INTERFACE_TYPE_CHOICES,
973 IPADDRESS_TYPE,
974+ NODE_TYPE,
975 NODEGROUPINTERFACE_MANAGEMENT,
976 )
977 from maasserver.exceptions import (
978@@ -540,7 +541,7 @@
979 """
980 is_on_device_with_parent = (
981 self.node is not None and
982- not self.node.installable and
983+ self.node.node_type == NODE_TYPE.DEVICE and
984 self.node.parent is not None)
985 if is_on_device_with_parent:
986 # Use the parents cluster interfaces.
987@@ -566,7 +567,7 @@
988 """
989 is_on_device_with_parent = (
990 self.node is not None and
991- not self.node.installable and
992+ self.node.node_type == NODE_TYPE.DEVICE and
993 self.node.parent is not None)
994 if is_on_device_with_parent:
995 # Use the parents cluster interfaces.
996@@ -1387,7 +1388,7 @@
997 interface belongs to a Device). Otherwise, return None.
998 """
999 if (self.node is not None and
1000- not self.node.installable and
1001+ self.node.node_type == NODE_TYPE.DEVICE and
1002 self.node.parent is not None):
1003 return self.node.parent
1004 else:
1005
1006=== modified file 'src/maasserver/models/node.py'
1007--- src/maasserver/models/node.py 2015-12-09 01:24:24 +0000
1008+++ src/maasserver/models/node.py 2015-12-18 15:12:10 +0000
1009@@ -65,6 +65,8 @@
1010 NODE_STATUS,
1011 NODE_STATUS_CHOICES,
1012 NODE_STATUS_CHOICES_DICT,
1013+ NODE_TYPE,
1014+ NODE_TYPE_CHOICES,
1015 POWER_STATE,
1016 POWER_STATE_CHOICES,
1017 PRESEED_TYPE,
1018@@ -400,19 +402,25 @@
1019
1020
1021 class GeneralManager(BaseNodeManager):
1022- """All the nodes: installable and non-installable together."""
1023+ """All the node types:"""
1024
1025
1026 class NodeManager(BaseNodeManager):
1027- """Installable nodes (i.e. non-devices objects)."""
1028+ """Nodes (i.e. deployable objects)."""
1029
1030- extra_filters = {'installable': True}
1031+ extra_filters = {'node_type': NODE_TYPE.MACHINE}
1032
1033
1034 class DeviceManager(BaseNodeManager):
1035- """Devices are all the non-installable nodes."""
1036-
1037- extra_filters = {'installable': False}
1038+ """Devices are all the non-deployable nodes."""
1039+
1040+ extra_filters = {'node_type': NODE_TYPE.DEVICE}
1041+
1042+
1043+class RackControllerManager(BaseNodeManager):
1044+ """Rack controllers are nodes which are used by MAAS to deploy nodes."""
1045+
1046+ extra_filters = {'node_type': NODE_TYPE.RACK_CONTROLLER}
1047
1048
1049 def patch_pgarray_types():
1050@@ -488,12 +496,11 @@
1051 :ivar system_id: The unique identifier for this `Node`.
1052 (e.g. 'node-41eba45e-4cfa-11e1-a052-00225f89f211').
1053 :ivar hostname: This `Node`'s hostname. Must conform to RFCs 952 and 1123.
1054- :ivar installable: An optional flag to indicate if this node can be
1055- installed or not. Non-installable nodes are nodes for which MAAS only
1056- manages DHCP and DNS.
1057+ :ivar node_type: The type of node. This is used to specify if the node is
1058+ to be used as a node for deployment, as a device, or a rack controller
1059 :ivar parent: An optional parent `Node`. This node will be deleted along
1060 with all its resources when the parent node gets deleted or released.
1061- This is only relevant for non-installable nodes.
1062+ This is only relevant for node types other than node.
1063 :ivar status: This `Node`'s status. See the vocabulary
1064 :class:`NODE_STATUS`.
1065 :ivar error_description: A human-readable description of why a node is
1066@@ -557,7 +564,8 @@
1067
1068 hwe_kernel = CharField(max_length=31, blank=True, null=True)
1069
1070- installable = BooleanField(default=True, db_index=True, editable=False)
1071+ node_type = IntegerField(
1072+ choices=NODE_TYPE_CHOICES, editable=False, default=NODE_TYPE.DEFAULT)
1073
1074 parent = ForeignKey(
1075 "Node", default=None, blank=True, null=True, editable=True,
1076@@ -684,15 +692,18 @@
1077 # the first manager defined is important: see
1078 # https://docs.djangoproject.com/en/1.7/topics/db/managers/ ("Default
1079 # managers") for details.
1080- # 'objects' are all the nodes: installable and non-installable together.
1081+ # 'objects' are all the nodes types
1082 objects = GeneralManager()
1083
1084- # 'nodes' are all the installable nodes (i.e. non-devices objects).
1085+ # 'nodes' are all of nodes of type node.
1086 nodes = NodeManager()
1087
1088- # 'devices' are all the non-installable nodes.
1089+ # 'devices' are all of node of type device
1090 devices = DeviceManager()
1091
1092+ # 'rack controller' are all of node of type rack_controller
1093+ rack_controllers = RackControllerManager()
1094+
1095 def __str__(self):
1096 if self.hostname:
1097 return "%s (%s)" % (self.system_id, self.fqdn)
1098@@ -1037,7 +1048,9 @@
1099 raise NodeStateViolation(error_text)
1100
1101 def clean_architecture(self, prev):
1102- if self.architecture == '' and self.installable:
1103+ if (self.architecture == '' and
1104+ (self.node_type == NODE_TYPE.MACHINE or
1105+ self.node_type == NODE_TYPE.RACK_CONTROLLER)):
1106 raise ValidationError(
1107 {'architecture':
1108 ["Architecture must be defined for installable nodes."]})
1109@@ -2673,4 +2686,5 @@
1110 proxy = True
1111
1112 def __init__(self, *args, **kwargs):
1113- super(Device, self).__init__(installable=False, *args, **kwargs)
1114+ super(Device, self).__init__(node_type=NODE_TYPE.DEVICE,
1115+ *args, **kwargs)
1116
1117=== modified file 'src/maasserver/models/signals/power.py'
1118--- src/maasserver/models/signals/power.py 2015-12-01 18:12:59 +0000
1119+++ src/maasserver/models/signals/power.py 2015-12-18 15:12:10 +0000
1120@@ -102,11 +102,6 @@
1121 # abandon this task; there's no point even logging.
1122 return
1123
1124- if not node.installable:
1125- # This is actually a device, not a node. We don't support power queries
1126- # for devices.
1127- return
1128-
1129 if power_info is None:
1130 # The node does not have a valid power type, so we can't query it.
1131 # Logging this is just spam; this problem is reported elsewhere, so
1132
1133=== modified file 'src/maasserver/models/staticipaddress.py'
1134--- src/maasserver/models/staticipaddress.py 2015-12-09 01:24:24 +0000
1135+++ src/maasserver/models/staticipaddress.py 2015-12-18 15:12:10 +0000
1136@@ -794,7 +794,7 @@
1137 data["node_summary"] = {
1138 "hostname": node.hostname,
1139 "system_id": node.system_id,
1140- "installable": node.installable,
1141+ "node_type": node.node_type,
1142 }
1143 if (with_username and
1144 self.alloc_type != IPADDRESS_TYPE.DISCOVERED):
1145
1146=== modified file 'src/maasserver/models/tests/test_node.py'
1147--- src/maasserver/models/tests/test_node.py 2015-12-01 18:12:59 +0000
1148+++ src/maasserver/models/tests/test_node.py 2015-12-18 15:12:10 +0000
1149@@ -32,6 +32,7 @@
1150 NODE_STATUS,
1151 NODE_STATUS_CHOICES,
1152 NODE_STATUS_CHOICES_DICT,
1153+ NODE_TYPE,
1154 NODEGROUP_STATUS,
1155 NODEGROUPINTERFACE_MANAGEMENT,
1156 POWER_STATE,
1157@@ -147,13 +148,19 @@
1158 self.assertThat(node.system_id, HasLength(41))
1159 self.assertTrue(node.system_id.startswith('node-'))
1160
1161- def test_empty_architecture_rejected_for_installable_nodes(self):
1162- self.assertRaises(
1163- ValidationError,
1164- factory.make_Node, installable=True, architecture='')
1165-
1166- def test_empty_architecture_accepted_for_non_installable_nodes(self):
1167- node = factory.make_Node(installable=False, architecture='')
1168+ def test_empty_architecture_rejected_for_type_node(self):
1169+ self.assertRaises(
1170+ ValidationError,
1171+ factory.make_Node, node_type=NODE_TYPE.MACHINE, architecture='')
1172+
1173+ def test_empty_architecture_rejected_for_type_rack_controller(self):
1174+ self.assertRaises(
1175+ ValidationError,
1176+ factory.make_Node, node_type=NODE_TYPE.RACK_CONTROLLER,
1177+ architecture='')
1178+
1179+ def test_empty_architecture_accepted_for_type_device(self):
1180+ node = factory.make_Node(node_type=NODE_TYPE.DEVICE, architecture='')
1181 self.assertThat(node, IsInstance(Node))
1182
1183 def test_hostname_is_validated(self):
1184@@ -1848,8 +1855,10 @@
1185 node.save)
1186
1187 def test_full_clean_checks_architecture_for_installable_nodes(self):
1188- node = factory.make_Node(installable=False, architecture='')
1189- node.installable = True
1190+ node = factory.make_Node(node_type=NODE_TYPE.DEVICE, architecture='')
1191+ # Set type here so we don't cause exception while creating object
1192+ node.node_type = factory.pick_enum(
1193+ NODE_TYPE, but_not=[NODE_TYPE.DEVICE])
1194 exception = self.assertRaises(ValidationError, node.full_clean)
1195 self.assertEqual(
1196 exception.message_dict,
1197@@ -2900,26 +2909,54 @@
1198 class TestAllNodeManagers(MAASServerTestCase):
1199 """Test the node's managers."""
1200
1201- def test_objects_lists_installable_nodes(self):
1202+ def test_nodes_lists_node_type_nodes(self):
1203 # Create nodes.
1204- nodes = [factory.make_Node(installable=True) for _ in range(3)]
1205+ nodes = [factory.make_Node(node_type=NODE_TYPE.MACHINE)
1206+ for _ in range(3)]
1207 # Create devices.
1208- [factory.make_Node(installable=False) for _ in range(3)]
1209+ [factory.make_Node(node_type=NODE_TYPE.DEVICE) for _ in range(3)]
1210+ # Create rack_controllers.
1211+ [factory.make_Node(node_type=NODE_TYPE.RACK_CONTROLLER)
1212+ for _ in range(3)]
1213 self.assertItemsEqual(nodes, Node.nodes.all())
1214
1215- def test_devices_lists_noninstallable_nodes(self):
1216+ def test_devices_lists_node_type_devices(self):
1217 # Create nodes.
1218- [factory.make_Node(installable=True) for _ in range(3)]
1219+ [factory.make_Node(node_type=NODE_TYPE.MACHINE) for _ in range(3)]
1220 # Create devices.
1221- devices = [factory.make_Node(installable=False) for _ in range(3)]
1222+ devices = [factory.make_Node(node_type=NODE_TYPE.DEVICE)
1223+ for _ in range(3)]
1224+ # Create rack_controllers.
1225+ [factory.make_Node(node_type=NODE_TYPE.RACK_CONTROLLER)
1226+ for _ in range(3)]
1227 self.assertItemsEqual(devices, Node.devices.all())
1228
1229- def test_all_lists_all_nodes(self):
1230- # Create nodes.
1231- nodes = [factory.make_Node(installable=True) for _ in range(3)]
1232- # Create devices.
1233- devices = [factory.make_Node(installable=False) for _ in range(3)]
1234- self.assertItemsEqual(nodes + devices, Node.objects.all())
1235+ def test_rack_controllers_lists_node_type_rack_controller(self):
1236+ # Create nodes.
1237+ [factory.make_Node(node_type=NODE_TYPE.MACHINE) for _ in range(3)]
1238+ # Create devices.
1239+ [factory.make_Node(node_type=NODE_TYPE.DEVICE) for _ in range(3)]
1240+ # Create rack_controllers.
1241+ rack_controllers = [
1242+ factory.make_Node(
1243+ node_type=NODE_TYPE.RACK_CONTROLLER)
1244+ for _ in range(3)]
1245+ self.assertItemsEqual(rack_controllers, Node.rack_controllers.all())
1246+
1247+ def test_objects_lists_all_nodes(self):
1248+ # Create nodes.
1249+ nodes = [factory.make_Node(node_type=NODE_TYPE.MACHINE)
1250+ for _ in range(3)]
1251+ # Create devices.
1252+ devices = [
1253+ factory.make_Node(node_type=NODE_TYPE.DEVICE) for _ in range(3)]
1254+ # Create rack_controllers.
1255+ rack_controllers = [
1256+ factory.make_Node(
1257+ node_type=NODE_TYPE.RACK_CONTROLLER)
1258+ for _ in range(3)]
1259+ self.assertItemsEqual(
1260+ nodes + devices + rack_controllers, Node.objects.all())
1261
1262
1263 class TestNodeTransitionMonitors(MAASServerTestCase):
1264
1265=== modified file 'src/maasserver/models/tests/test_staticipaddress.py'
1266--- src/maasserver/models/tests/test_staticipaddress.py 2015-12-01 18:12:59 +0000
1267+++ src/maasserver/models/tests/test_staticipaddress.py 2015-12-18 15:12:10 +0000
1268@@ -1107,4 +1107,4 @@
1269 node_summary = json["node_summary"]
1270 self.expectThat(node_summary["hostname"], Equals(node.hostname))
1271 self.expectThat(node_summary["system_id"], Equals(node.system_id))
1272- self.expectThat(node_summary["installable"], Equals(node.installable))
1273+ self.expectThat(node_summary["node_type"], Equals(node.node_type))
1274
1275=== modified file 'src/maasserver/models/tests/test_zone.py'
1276--- src/maasserver/models/tests/test_zone.py 2015-12-01 18:12:59 +0000
1277+++ src/maasserver/models/tests/test_zone.py 2015-12-18 15:12:10 +0000
1278@@ -5,6 +5,7 @@
1279
1280 __all__ = []
1281
1282+from maasserver.enum import NODE_TYPE
1283 from maasserver.models.zone import (
1284 DEFAULT_ZONE_NAME,
1285 Zone,
1286@@ -72,31 +73,55 @@
1287 self.assertFalse(factory.make_Zone().is_default())
1288
1289 def test_nodes_only_set(self):
1290- """zone.nodes_olny_set has all installable nodes."""
1291+ """zone.node_only_set has only type node."""
1292 zone = factory.make_Zone()
1293- node1 = factory.make_Node(zone=zone, installable=True)
1294- node2 = factory.make_Node(zone=zone, installable=True)
1295- node3 = factory.make_Node(zone=zone, installable=True)
1296- device1 = factory.make_Node(zone=zone, installable=False)
1297- device2 = factory.make_Node(zone=zone, installable=False)
1298+ node1 = factory.make_Node(zone=zone, node_type=NODE_TYPE.MACHINE)
1299+ node2 = factory.make_Node(zone=zone, node_type=NODE_TYPE.MACHINE)
1300+ node3 = factory.make_Node(zone=zone, node_type=NODE_TYPE.MACHINE)
1301+ device1 = factory.make_Node(zone=zone, node_type=NODE_TYPE.DEVICE)
1302+ device2 = factory.make_Node(zone=zone, node_type=NODE_TYPE.DEVICE)
1303+ rack_controller = factory.make_Node(
1304+ zone=zone, node_type=NODE_TYPE.RACK_CONTROLLER)
1305 self.assertEqual(zone.node_only_set.count(), 3)
1306 self.assertIn(node1, zone.node_only_set)
1307 self.assertIn(node2, zone.node_only_set)
1308 self.assertIn(node3, zone.node_only_set)
1309 self.assertNotIn(device1, zone.node_only_set)
1310 self.assertNotIn(device2, zone.node_only_set)
1311+ self.assertNotIn(rack_controller, zone.node_only_set)
1312
1313 def test_devices_only_set(self):
1314- """zone.devices_only_set has all non-installable nodes."""
1315+ """zone.devices_only_set has only type device."""
1316 zone = factory.make_Zone()
1317- node1 = factory.make_Node(zone=zone, installable=True)
1318- node2 = factory.make_Node(zone=zone, installable=True)
1319- node3 = factory.make_Node(zone=zone, installable=True)
1320- device1 = factory.make_Node(zone=zone, installable=False)
1321- device2 = factory.make_Node(zone=zone, installable=False)
1322+ node1 = factory.make_Node(zone=zone, node_type=NODE_TYPE.MACHINE)
1323+ node2 = factory.make_Node(zone=zone, node_type=NODE_TYPE.MACHINE)
1324+ node3 = factory.make_Node(zone=zone, node_type=NODE_TYPE.MACHINE)
1325+ device1 = factory.make_Node(zone=zone, node_type=NODE_TYPE.DEVICE)
1326+ device2 = factory.make_Node(zone=zone, node_type=NODE_TYPE.DEVICE)
1327+ rack_controller = factory.make_Node(
1328+ zone=zone, node_type=NODE_TYPE.RACK_CONTROLLER)
1329 self.assertEqual(zone.device_only_set.count(), 2)
1330 self.assertNotIn(node1, zone.device_only_set)
1331 self.assertNotIn(node2, zone.device_only_set)
1332 self.assertNotIn(node3, zone.device_only_set)
1333 self.assertIn(device1, zone.device_only_set)
1334 self.assertIn(device2, zone.device_only_set)
1335+ self.assertNotIn(rack_controller, zone.node_only_set)
1336+
1337+ def test_rack_controllers_only_set(self):
1338+ """zone.rack_controllers_only_set has only type rack_controller."""
1339+ zone = factory.make_Zone()
1340+ node1 = factory.make_Node(zone=zone, node_type=NODE_TYPE.MACHINE)
1341+ node2 = factory.make_Node(zone=zone, node_type=NODE_TYPE.MACHINE)
1342+ node3 = factory.make_Node(zone=zone, node_type=NODE_TYPE.MACHINE)
1343+ device1 = factory.make_Node(zone=zone, node_type=NODE_TYPE.DEVICE)
1344+ device2 = factory.make_Node(zone=zone, node_type=NODE_TYPE.DEVICE)
1345+ rack_controller = factory.make_Node(
1346+ zone=zone, node_type=NODE_TYPE.RACK_CONTROLLER)
1347+ self.assertEqual(zone.device_only_set.count(), 2)
1348+ self.assertNotIn(node1, zone.rack_controller_only_set)
1349+ self.assertNotIn(node2, zone.rack_controller_only_set)
1350+ self.assertNotIn(node3, zone.rack_controller_only_set)
1351+ self.assertNotIn(device1, zone.rack_controller_only_set)
1352+ self.assertNotIn(device2, zone.rack_controller_only_set)
1353+ self.assertIn(rack_controller, zone.rack_controller_only_set)
1354
1355=== modified file 'src/maasserver/models/zone.py'
1356--- src/maasserver/models/zone.py 2015-12-01 18:12:59 +0000
1357+++ src/maasserver/models/zone.py 2015-12-18 15:12:10 +0000
1358@@ -19,6 +19,7 @@
1359 TextField,
1360 )
1361 from maasserver import DefaultMeta
1362+from maasserver.enum import NODE_TYPE
1363 from maasserver.models.cleansave import CleanSave
1364 from maasserver.models.timestampedmodel import TimestampedModel
1365
1366@@ -88,10 +89,15 @@
1367
1368 @property
1369 def node_only_set(self):
1370- """Returns just the installable nodes in this zone"""
1371- return self.node_set.filter(installable=True)
1372+ """Returns just the nodes of node_type node in this zone."""
1373+ return self.node_set.filter(node_type=NODE_TYPE.MACHINE)
1374
1375 @property
1376 def device_only_set(self):
1377- """Returns the non-installable nodes in this zone"""
1378- return self.node_set.filter(installable=False)
1379+ """Returns just the nodes of node_type device in this zone."""
1380+ return self.node_set.filter(node_type=NODE_TYPE.DEVICE)
1381+
1382+ @property
1383+ def rack_controller_only_set(self):
1384+ """Returns just the nodes of node_type rack controller in this zone."""
1385+ return self.node_set.filter(node_type=NODE_TYPE.RACK_CONTROLLER)
1386
1387=== modified file 'src/maasserver/node_action.py'
1388--- src/maasserver/node_action.py 2015-12-01 18:12:59 +0000
1389+++ src/maasserver/node_action.py 2015-12-18 15:12:10 +0000
1390@@ -30,6 +30,7 @@
1391 NODE_PERMISSION,
1392 NODE_STATUS,
1393 NODE_STATUS_CHOICES_DICT,
1394+ NODE_TYPE,
1395 POWER_STATE,
1396 )
1397 from maasserver.exceptions import (
1398@@ -82,10 +83,10 @@
1399 Will be used as the label for the action's button.
1400 """)
1401
1402- installable_only = abstractproperty("""
1403- Can only be performed on a installable node.
1404+ node_only = abstractproperty("""
1405+ Can only be performed when the node type is node.
1406
1407- A boolean value. True for only available for installable node, false
1408+ A boolean value. True for only available for node_type node, false
1409 otherwise.
1410 """)
1411
1412@@ -103,9 +104,9 @@
1413 user has this given permission on the subject node.
1414 """)
1415
1416- # Optional installable permission that will be used when the action
1417- # is being applied to a node that is installable.
1418- installable_permission = None
1419+ # Optional node permission that will be used when the action
1420+ # is being applied to a node_type which is node
1421+ node_permission = None
1422
1423 def __init__(self, node, user, request=None):
1424 """Initialize a node action.
1425@@ -120,12 +121,12 @@
1426 def is_actionable(self):
1427 """Can this action be performed?
1428
1429- If the node is not installable then actionable_statuses will not
1430- be used, as the status doesn't matter for an uninstallable node.
1431+ If the node is not node_type node then actionable_statuses will not
1432+ be used, as the status doesn't matter for a non-node type.
1433 """
1434- if self.installable_only and not self.node.installable:
1435+ if self.node_only and not self.node.node_type == NODE_TYPE.MACHINE:
1436 return False
1437- if self.node.installable:
1438+ if self.node.node_type == NODE_TYPE.MACHINE:
1439 return self.node.status in self.actionable_statuses
1440 return True
1441
1442@@ -151,10 +152,10 @@
1443 """
1444
1445 def get_permission(self):
1446- """Return the permission value depending on if the node is
1447- installable or not."""
1448- if self.node.installable and self.installable_permission is not None:
1449- return self.installable_permission
1450+ """Return the permission value depending on if the node_type."""
1451+ if(self.node.node_type == NODE_TYPE.MACHINE and
1452+ self.node_permission is not None):
1453+ return self.node_permission
1454 return self.permission
1455
1456 def is_permitted(self):
1457@@ -179,8 +180,8 @@
1458 display_sentence = "deleted"
1459 actionable_statuses = ALL_STATUSES
1460 permission = NODE_PERMISSION.EDIT
1461- installable_permission = NODE_PERMISSION.ADMIN
1462- installable_only = False
1463+ node_permission = NODE_PERMISSION.ADMIN
1464+ node_only = False
1465
1466 def execute(self):
1467 """Redirect to the delete view's confirmation page.
1468@@ -199,8 +200,8 @@
1469 display_sentence = "Zone set"
1470 actionable_statuses = ALL_STATUSES
1471 permission = NODE_PERMISSION.EDIT
1472- installable_permission = NODE_PERMISSION.ADMIN
1473- installable_only = False
1474+ node_permission = NODE_PERMISSION.ADMIN
1475+ node_only = False
1476
1477 def execute(self, zone_id=None):
1478 """See `NodeAction.execute`."""
1479@@ -224,7 +225,7 @@
1480 NODE_STATUS.BROKEN,
1481 )
1482 permission = NODE_PERMISSION.ADMIN
1483- installable_only = True
1484+ node_only = True
1485
1486 def execute(
1487 self, enable_ssh=False, skip_networking=False,
1488@@ -255,7 +256,7 @@
1489 NODE_STATUS.DEPLOYING
1490 )
1491 permission = NODE_PERMISSION.ADMIN
1492- installable_only = True
1493+ node_only = True
1494
1495 def execute(self):
1496 """See `NodeAction.execute`."""
1497@@ -272,7 +273,7 @@
1498 display_sentence = "acquired"
1499 actionable_statuses = (NODE_STATUS.READY, )
1500 permission = NODE_PERMISSION.VIEW
1501- installable_only = True
1502+ node_only = True
1503
1504 def execute(self):
1505 """See `NodeAction.execute`."""
1506@@ -287,7 +288,7 @@
1507 display_sentence = "deployed"
1508 actionable_statuses = (NODE_STATUS.READY, NODE_STATUS.ALLOCATED)
1509 permission = NODE_PERMISSION.VIEW
1510- installable_only = True
1511+ node_only = True
1512
1513 def execute(self, osystem=None, distro_series=None, hwe_kernel=None):
1514 """See `NodeAction.execute`."""
1515@@ -333,7 +334,7 @@
1516 NODE_STATUS.BROKEN,
1517 )
1518 permission = NODE_PERMISSION.EDIT
1519- installable_only = True
1520+ node_only = True
1521
1522 def execute(self):
1523 """See `NodeAction.execute`."""
1524@@ -365,7 +366,7 @@
1525 # Let a user power off a node in any non-active status.
1526 actionable_statuses = NON_MONITORED_STATUSES
1527 permission = NODE_PERMISSION.EDIT
1528- installable_only = True
1529+ node_only = True
1530
1531 def execute(self):
1532 """See `NodeAction.execute`."""
1533@@ -394,7 +395,7 @@
1534 NODE_STATUS.FAILED_DISK_ERASING,
1535 )
1536 permission = NODE_PERMISSION.EDIT
1537- installable_only = True
1538+ node_only = True
1539
1540 def execute(self):
1541 """See `NodeAction.execute`."""
1542@@ -422,7 +423,7 @@
1543 NODE_STATUS.DISK_ERASING,
1544 ] + FAILED_STATUSES
1545 permission = NODE_PERMISSION.EDIT
1546- installable_only = True
1547+ node_only = True
1548
1549 def execute(self):
1550 """See `NodeAction.execute`."""
1551@@ -436,7 +437,7 @@
1552 display_sentence = "marked fixed"
1553 actionable_statuses = (NODE_STATUS.BROKEN, )
1554 permission = NODE_PERMISSION.ADMIN
1555- installable_only = True
1556+ node_only = True
1557
1558 def execute(self):
1559 """See `NodeAction.execute`."""
1560
1561=== modified file 'src/maasserver/rpc/nodes.py'
1562--- src/maasserver/rpc/nodes.py 2015-12-01 18:12:59 +0000
1563+++ src/maasserver/rpc/nodes.py 2015-12-18 15:12:10 +0000
1564@@ -74,7 +74,6 @@
1565 .filter(power_state_updated=None)
1566 .filter(power_type__in=QUERY_POWER_TYPES)
1567 .exclude(status=NODE_STATUS.BROKEN)
1568- .exclude(installable=False)
1569 )
1570 nodes_checked = (
1571 nodes
1572@@ -82,7 +81,6 @@
1573 .exclude(power_state_updated__gt=five_minutes_ago)
1574 .filter(power_type__in=QUERY_POWER_TYPES)
1575 .exclude(status=NODE_STATUS.BROKEN)
1576- .exclude(installable=False)
1577 .order_by("power_state_updated", "system_id")
1578 )
1579
1580
1581=== modified file 'src/maasserver/rpc/tests/test_nodes.py'
1582--- src/maasserver/rpc/tests/test_nodes.py 2015-12-01 18:12:59 +0000
1583+++ src/maasserver/rpc/tests/test_nodes.py 2015-12-18 15:12:10 +0000
1584@@ -393,14 +393,14 @@
1585
1586 self.assertItemsEqual([node_queryable.system_id], system_ids)
1587
1588- def test__excludes_devices(self):
1589+ def test__excludes_no_power_type(self):
1590 cluster = factory.make_NodeGroup()
1591 node_queryable = self.make_Node(cluster)
1592
1593- factory.make_Device(nodegroup=cluster)
1594- factory.make_Device(nodegroup=cluster, power_type="ipmi")
1595+ factory.make_Device(nodegroup=cluster, power_type='')
1596+ factory.make_Device(nodegroup=cluster, power_type='')
1597 factory.make_Device(
1598- nodegroup=cluster, power_type="ipmi", power_state_updated=(
1599+ nodegroup=cluster, power_type='', power_state_updated=(
1600 now() - timedelta(minutes=10)))
1601
1602 power_parameters = list_cluster_nodes_power_parameters(cluster.uuid)
1603
1604=== modified file 'src/maasserver/static/partials/subnet-details.html'
1605--- src/maasserver/static/partials/subnet-details.html 2015-10-01 03:31:04 +0000
1606+++ src/maasserver/static/partials/subnet-details.html 2015-12-18 15:12:10 +0000
1607@@ -61,8 +61,15 @@
1608 <div class="table__row" data-ng-repeat="ip in subnet.ip_addresses">
1609 <div class="table__data table__column--15">{$ ip.ip $}</div>
1610 <div class="table__data table__column--15">{$ ip.user $}</div>
1611- <div class="table__data table__column--20"><a href="#/node/{$ ip.node_summary.system_id $}" data-ng-if="ip.node_summary.installable">{$ ip.node_summary.hostname $}</a><span data-ng-if="!ip.node_summary.installable">{$ ip.node_summary.hostname $}</span></div>
1612- <div class="table__data table__column--15">{$ ip.node_summary.installable ? "Node" : "Device" $}</div>
1613+ <div class="table__data table__column--20">
1614+ <!--
1615+ XXX ltrager 2015-12-02
1616+ node_type is an enum of node(0), device(1), or rack_controller(2). We need to create some type of Javascript enum to represent this
1617+ -->
1618+ <a href="#/node/{$ ip.node_summary.system_id $}" data-ng-if="ip.node_summary.node_type == 0">{$ ip.node_summary.hostname $}</a>
1619+ <span data-ng-if="ip.node_summary.node_type == 1">{$ ip.node_summary.hostname $}</span>
1620+ </div>
1621+ <div class="table__data table__column--15">{$ ip.node_summary.node_type == 0 ? "Node" : "Device" $}</div>
1622 <div class="table__data table__column--35" data-ng-switch="ip.alloc_type">
1623 <span data-ng-switch-when="0">Automatic</span>
1624 <span data-ng-switch-when="1">Sticky</span>
1625
1626=== modified file 'src/maasserver/testing/factory.py'
1627--- src/maasserver/testing/factory.py 2015-12-11 01:48:39 +0000
1628+++ src/maasserver/testing/factory.py 2015-12-18 15:12:10 +0000
1629@@ -33,6 +33,7 @@
1630 IPADDRESS_TYPE,
1631 NODE_BOOT,
1632 NODE_STATUS,
1633+ NODE_TYPE,
1634 NODEGROUP_STATUS,
1635 NODEGROUPINTERFACE_MANAGEMENT,
1636 PARTITION_TABLE_TYPE,
1637@@ -254,22 +255,30 @@
1638 finally:
1639 NODE_TRANSITIONS[None] = valid_initial_states
1640
1641- def make_Device(self, hostname=None, nodegroup=None, **kwargs):
1642+ def make_Device(self, hostname=None, nodegroup=None, interface=False,
1643+ disable_ipv4=None, vlan=None, fabric=None, **kwargs):
1644 if hostname is None:
1645 hostname = self.make_string(20)
1646 if nodegroup is None:
1647 nodegroup = self.make_NodeGroup()
1648- device = Device(hostname=hostname, nodegroup=nodegroup, **kwargs)
1649+ if disable_ipv4 is None:
1650+ disable_ipv4 = self.pick_bool()
1651+ device = Device(hostname=hostname, nodegroup=nodegroup,
1652+ disable_ipv4=disable_ipv4, **kwargs)
1653 device.save()
1654- return device
1655+ if interface:
1656+ self.make_Interface(
1657+ INTERFACE_TYPE.PHYSICAL, node=device, vlan=vlan, fabric=fabric)
1658+ return reload_object(device)
1659
1660 def make_Node(
1661 self, interface=False, hostname=None, status=None,
1662- architecture="i386/generic", min_hwe_kernel=None, hwe_kernel=None,
1663- installable=True, updated=None, created=None, nodegroup=None,
1664- routers=None, zone=None, networks=None, boot_type=None,
1665- sortable_name=False, power_type=None, power_parameters=None,
1666- power_state=None, power_state_updated=undefined, disable_ipv4=None,
1667+ architecture="i386/generic", min_hwe_kernel=None,
1668+ hwe_kernel=None, node_type=NODE_TYPE.MACHINE, updated=None,
1669+ created=None, nodegroup=None, routers=None, zone=None,
1670+ networks=None, boot_type=None, sortable_name=False,
1671+ power_type=None, power_parameters=None, power_state=None,
1672+ power_state_updated=undefined, disable_ipv4=None,
1673 with_boot_disk=True, vlan=None, fabric=None, **kwargs):
1674 """Make a :class:`Node`.
1675
1676@@ -308,7 +317,7 @@
1677 node = Node(
1678 hostname=hostname, status=status, architecture=architecture,
1679 min_hwe_kernel=min_hwe_kernel, hwe_kernel=hwe_kernel,
1680- installable=installable, nodegroup=nodegroup, routers=routers,
1681+ node_type=node_type, nodegroup=nodegroup, routers=routers,
1682 zone=zone, boot_type=boot_type, power_type=power_type,
1683 power_parameters=power_parameters, power_state=power_state,
1684 power_state_updated=power_state_updated, disable_ipv4=disable_ipv4,
1685@@ -322,7 +331,7 @@
1686 if interface:
1687 self.make_Interface(
1688 INTERFACE_TYPE.PHYSICAL, node=node, vlan=vlan, fabric=fabric)
1689- if installable and with_boot_disk:
1690+ if node_type == NODE_TYPE.MACHINE and with_boot_disk:
1691 root_partition = self.make_Partition(node=node)
1692 acquired = node.status in ALLOCATED_NODE_STATUSES
1693 self.make_Filesystem(
1694
1695=== modified file 'src/maasserver/tests/test_auth.py'
1696--- src/maasserver/tests/test_auth.py 2015-12-07 16:37:36 +0000
1697+++ src/maasserver/tests/test_auth.py 2015-12-18 15:12:10 +0000
1698@@ -229,8 +229,8 @@
1699 backend = MAASAuthorizationBackend()
1700 user = factory.make_User()
1701 parent = factory.make_Node()
1702- device = factory.make_Node(
1703- owner=user, installable=False, parent=parent)
1704+ device = factory.make_Device(
1705+ owner=user, parent=parent)
1706 interface = factory.make_Interface(
1707 INTERFACE_TYPE.PHYSICAL, node=device)
1708 self.assertTrue(
1709@@ -242,8 +242,8 @@
1710 user = factory.make_User()
1711 owner = factory.make_User()
1712 parent = factory.make_Node()
1713- device = factory.make_Node(
1714- owner=owner, installable=False, parent=parent)
1715+ device = factory.make_Device(
1716+ owner=owner, parent=parent)
1717 interface = factory.make_Interface(
1718 INTERFACE_TYPE.PHYSICAL, node=device)
1719 self.assertFalse(
1720
1721=== modified file 'src/maasserver/tests/test_listener.py'
1722--- src/maasserver/tests/test_listener.py 2015-12-07 14:33:41 +0000
1723+++ src/maasserver/tests/test_listener.py 2015-12-18 15:12:10 +0000
1724@@ -16,6 +16,7 @@
1725 from maasserver.enum import (
1726 INTERFACE_TYPE,
1727 IPADDRESS_TYPE,
1728+ NODE_TYPE,
1729 )
1730 from maasserver.listener import (
1731 PostgresListenerNotifyError,
1732@@ -464,7 +465,7 @@
1733 if params is None:
1734 params = {}
1735 parent = factory.make_Node(with_boot_disk=False)
1736- params["installable"] = False
1737+ params["node_type"] = NODE_TYPE.DEVICE
1738 params["parent"] = parent
1739 device = factory.make_Node(**params)
1740 return device, parent
1741@@ -915,11 +916,11 @@
1742
1743 scenarios = (
1744 ('node', {
1745- 'params': {'installable': True},
1746+ 'params': {'node_type': NODE_TYPE.MACHINE},
1747 'listener': 'node',
1748 }),
1749 ('device', {
1750- 'params': {'installable': False},
1751+ 'params': {'node_type': NODE_TYPE.DEVICE},
1752 'listener': 'device',
1753 }),
1754 )
1755@@ -991,7 +992,7 @@
1756 try:
1757 yield deferToDatabase(
1758 self.create_node, {
1759- "installable": False,
1760+ "node_type": NODE_TYPE.DEVICE,
1761 "parent": parent,
1762 })
1763 yield dv.get(timeout=2)
1764@@ -1298,11 +1299,11 @@
1765
1766 scenarios = (
1767 ('node', {
1768- 'params': {'installable': True},
1769+ 'params': {'node_type': NODE_TYPE.MACHINE},
1770 'listener': 'node',
1771 }),
1772 ('device', {
1773- 'params': {'installable': False},
1774+ 'params': {'node_type': NODE_TYPE.DEVICE},
1775 'listener': 'device',
1776 }),
1777 )
1778@@ -1545,11 +1546,11 @@
1779
1780 scenarios = (
1781 ('node', {
1782- 'params': {'installable': True},
1783+ 'params': {'node_type': NODE_TYPE.MACHINE},
1784 'listener': 'node',
1785 }),
1786 ('device', {
1787- 'params': {'installable': False},
1788+ 'params': {'node_type': NODE_TYPE.DEVICE},
1789 'listener': 'device',
1790 }),
1791 )
1792@@ -1602,11 +1603,11 @@
1793
1794 scenarios = (
1795 ('node', {
1796- 'params': {'installable': True, 'interface': True},
1797+ 'params': {'node_type': NODE_TYPE.MACHINE, 'interface': True},
1798 'listener': 'node',
1799 }),
1800 ('device', {
1801- 'params': {'installable': False, 'interface': True},
1802+ 'params': {'node_type': NODE_TYPE.DEVICE, 'interface': True},
1803 'listener': 'device',
1804 }),
1805 )
1806@@ -1709,11 +1710,11 @@
1807
1808 scenarios = (
1809 ('node', {
1810- 'params': {'installable': True},
1811+ 'params': {'node_type': NODE_TYPE.MACHINE},
1812 'listener': 'node',
1813 }),
1814 ('device', {
1815- 'params': {'installable': False},
1816+ 'params': {'node_type': NODE_TYPE.DEVICE},
1817 'listener': 'device',
1818 }),
1819 )
1820@@ -1803,11 +1804,11 @@
1821
1822 scenarios = (
1823 ('node', {
1824- 'params': {'installable': True},
1825+ 'params': {'node_type': NODE_TYPE.MACHINE},
1826 'listener': 'node',
1827 }),
1828 ('device', {
1829- 'params': {'installable': False},
1830+ 'params': {'node_type': NODE_TYPE.DEVICE},
1831 'listener': 'device',
1832 }),
1833 )
1834@@ -2238,11 +2239,11 @@
1835
1836 scenarios = (
1837 ('node', {
1838- 'params': {'installable': True, 'interface': True},
1839+ 'params': {'node_type': NODE_TYPE.MACHINE, 'interface': True},
1840 'listener': 'node',
1841 }),
1842 ('device', {
1843- 'params': {'installable': False, 'interface': True},
1844+ 'params': {'node_type': NODE_TYPE.DEVICE, 'interface': True},
1845 'listener': 'device',
1846 }),
1847 )
1848@@ -2590,7 +2591,7 @@
1849
1850 scenarios = (
1851 ('node', {
1852- 'params': {'installable': True},
1853+ 'params': {'node_type': NODE_TYPE.MACHINE},
1854 'listener': 'node',
1855 }),
1856 )
1857@@ -2704,7 +2705,7 @@
1858
1859 scenarios = (
1860 ('node', {
1861- 'params': {'installable': True},
1862+ 'params': {'node_type': NODE_TYPE.MACHINE},
1863 'listener': 'node',
1864 }),
1865 )
1866@@ -2776,7 +2777,7 @@
1867
1868 scenarios = (
1869 ('node', {
1870- 'params': {'installable': True},
1871+ 'params': {'node_type': NODE_TYPE.MACHINE},
1872 'listener': 'node',
1873 }),
1874 )
1875@@ -2849,7 +2850,7 @@
1876
1877 scenarios = (
1878 ('node', {
1879- 'params': {'installable': True},
1880+ 'params': {'node_type': NODE_TYPE.MACHINE},
1881 'listener': 'node',
1882 }),
1883 )
1884@@ -2926,7 +2927,7 @@
1885
1886 scenarios = (
1887 ('node', {
1888- 'params': {'installable': True, 'with_boot_disk': True},
1889+ 'params': {'node_type': NODE_TYPE.MACHINE, 'with_boot_disk': True},
1890 'listener': 'node',
1891 }),
1892 )
1893@@ -3003,7 +3004,7 @@
1894
1895 scenarios = (
1896 ('node', {
1897- 'params': {'installable': True},
1898+ 'params': {'node_type': NODE_TYPE.MACHINE},
1899 'listener': 'node',
1900 }),
1901 )
1902
1903=== modified file 'src/maasserver/tests/test_node_action.py'
1904--- src/maasserver/tests/test_node_action.py 2015-12-01 18:12:59 +0000
1905+++ src/maasserver/tests/test_node_action.py 2015-12-18 15:12:10 +0000
1906@@ -13,6 +13,7 @@
1907 NODE_STATUS,
1908 NODE_STATUS_CHOICES,
1909 NODE_STATUS_CHOICES_DICT,
1910+ NODE_TYPE,
1911 POWER_STATE,
1912 )
1913 from maasserver.exceptions import NodeActionError
1914@@ -70,7 +71,7 @@
1915 display = "Action label"
1916 actionable_statuses = ALL_STATUSES
1917 permission = NODE_PERMISSION.VIEW
1918- installable_only = False
1919+ node_only = False
1920
1921 # For testing: an inhibition for inhibit() to return.
1922 fake_inhibition = None
1923@@ -165,25 +166,25 @@
1924 status=NODE_STATUS.ALLOCATED, owner=factory.make_User())
1925 self.assertFalse(MyAction(node, factory.make_User()).is_permitted())
1926
1927- def test_is_permitted_uses_installable_permission(self):
1928+ def test_is_permitted_uses_node_permission(self):
1929
1930 class MyAction(FakeNodeAction):
1931 permission = NODE_PERMISSION.VIEW
1932- installable_permission = NODE_PERMISSION.EDIT
1933+ node_permission = NODE_PERMISSION.EDIT
1934
1935 node = factory.make_Node(
1936 status=NODE_STATUS.ALLOCATED, owner=factory.make_User())
1937 self.assertFalse(MyAction(node, factory.make_User()).is_permitted())
1938
1939- def test_is_permitted_doest_use_installable_permission_if_device(self):
1940+ def test_is_permitted_doest_use_node_permission_if_device(self):
1941
1942 class MyAction(FakeNodeAction):
1943 permission = NODE_PERMISSION.VIEW
1944- installable_permission = NODE_PERMISSION.EDIT
1945+ node_permission = NODE_PERMISSION.EDIT
1946
1947 node = factory.make_Node(
1948 status=NODE_STATUS.ALLOCATED, owner=factory.make_User(),
1949- installable=False)
1950+ node_type=NODE_TYPE.DEVICE)
1951 self.assertTrue(MyAction(node, factory.make_User()).is_permitted())
1952
1953 def test_inhibition_wraps_inhibit(self):
1954@@ -213,22 +214,22 @@
1955 action.fake_inhibition = factory.make_string()
1956 self.assertIsNone(action.inhibition)
1957
1958- def test_installable_only_is_not_actionable_if_node_isnt_installable(self):
1959+ def test_node_only_is_not_actionable_if_node_isnt_node_type(self):
1960 status = NODE_STATUS.NEW
1961 owner = factory.make_User()
1962 node = factory.make_Node(
1963- owner=owner, status=status, installable=False)
1964+ owner=owner, status=status, node_type=NODE_TYPE.DEVICE)
1965 action = FakeNodeAction(node, owner)
1966- action.installable_only = True
1967+ action.node_only = True
1968 self.assertFalse(action.is_actionable())
1969
1970- def test_installable_only_is_actionable_if_node_is_installable(self):
1971+ def test_node_only_is_actionable_if_node_type_is_node(self):
1972 status = NODE_STATUS.NEW
1973 owner = factory.make_User()
1974 node = factory.make_Node(
1975- owner=owner, status=status, installable=True)
1976+ owner=owner, status=status, node_type=NODE_TYPE.MACHINE)
1977 action = FakeNodeAction(node, owner)
1978- action.installable_only = True
1979+ action.node_only = True
1980 self.assertTrue(action.is_actionable())
1981
1982 def test_is_actionable_checks_node_status_in_actionable_status(self):
1983
1984=== modified file 'src/maasserver/triggers.py'
1985--- src/maasserver/triggers.py 2015-12-01 18:12:59 +0000
1986+++ src/maasserver/triggers.py 2015-12-18 15:12:10 +0000
1987@@ -24,6 +24,7 @@
1988 from textwrap import dedent
1989
1990 from django.db import connection
1991+from maasserver.enum import NODE_TYPE
1992 from maasserver.utils.orm import transactional
1993
1994 # Note that the corresponding test module (test_triggers) only tests that the
1995@@ -35,18 +36,18 @@
1996
1997 # Procedure that is called when a tag is added or removed from a node/device.
1998 # Sends a notify message for node_update or device_update depending on if the
1999-# node is installable.
2000+# node type is node.
2001 NODE_TAG_NOTIFY = dedent("""\
2002 CREATE OR REPLACE FUNCTION %s() RETURNS trigger AS $$
2003 DECLARE
2004 node RECORD;
2005 pnode RECORD;
2006 BEGIN
2007- SELECT system_id, installable, parent_id INTO node
2008+ SELECT system_id, node_type, parent_id INTO node
2009 FROM maasserver_node
2010 WHERE id = %s;
2011
2012- IF node.installable THEN
2013+ IF node.node_type = %d THEN
2014 PERFORM pg_notify('node_update',CAST(node.system_id AS text));
2015 ELSIF node.parent_id IS NOT NULL THEN
2016 SELECT system_id INTO pnode
2017@@ -74,13 +75,13 @@
2018 FOR node IN (
2019 SELECT
2020 maasserver_node.system_id,
2021- maasserver_node.installable,
2022+ maasserver_node.node_type,
2023 maasserver_node.parent_id
2024 FROM maasserver_node_tags, maasserver_node
2025 WHERE maasserver_node_tags.tag_id = NEW.id
2026 AND maasserver_node_tags.node_id = maasserver_node.id)
2027 LOOP
2028- IF node.installable THEN
2029+ IF node.node_type = %d THEN
2030 PERFORM pg_notify('node_update',CAST(node.system_id AS text));
2031 ELSIF node.parent_id IS NOT NULL THEN
2032 SELECT system_id INTO pnode
2033@@ -99,7 +100,7 @@
2034
2035 # Procedure that is called when a event is created.
2036 # Sends a notify message for node_update or device_update depending on if the
2037-# link node is installable.
2038+# link node type is a node.
2039 EVENT_NODE_NOTIFY = dedent("""\
2040 CREATE OR REPLACE FUNCTION event_create_node_device_notify()
2041 RETURNS trigger AS $$
2042@@ -107,11 +108,11 @@
2043 node RECORD;
2044 pnode RECORD;
2045 BEGIN
2046- SELECT system_id, installable, parent_id INTO node
2047+ SELECT system_id, node_type, parent_id INTO node
2048 FROM maasserver_node
2049 WHERE id = NEW.node_id;
2050
2051- IF node.installable THEN
2052+ IF node.node_type = %d THEN
2053 PERFORM pg_notify('node_update',CAST(node.system_id AS text));
2054 ELSIF node.parent_id IS NOT NULL THEN
2055 SELECT system_id INTO pnode
2056@@ -167,19 +168,19 @@
2057
2058 # Procedure that is called when a static ip address is linked or unlinked to
2059 # an Interface. Sends a notify message for node_update or device_update
2060-# depending on if the node is installable.
2061+# depending on if the node type is node.
2062 INTERFACE_IP_ADDRESS_NODE_NOTIFY = dedent("""\
2063 CREATE OR REPLACE FUNCTION %s() RETURNS trigger AS $$
2064 DECLARE
2065 node RECORD;
2066 pnode RECORD;
2067 BEGIN
2068- SELECT system_id, installable, parent_id INTO node
2069+ SELECT system_id, node_type, parent_id INTO node
2070 FROM maasserver_node, maasserver_interface
2071 WHERE maasserver_node.id = maasserver_interface.node_id
2072 AND maasserver_interface.id = %s;
2073
2074- IF node.installable THEN
2075+ IF node.node_type = %d THEN
2076 PERFORM pg_notify('node_update',CAST(node.system_id AS text));
2077 ELSIF node.parent_id IS NOT NULL THEN
2078 SELECT system_id INTO pnode
2079@@ -198,8 +199,8 @@
2080 # Procedure that is called when a Interface address updated. Will send
2081 # node_update or device_update when the Interface is moved from another node
2082 # to a new node. Sends a notify message for node_update or device_update
2083-# depending on if the node is installable, both for the old node and the
2084-# new node.
2085+# depending on if the node type is node, both for the old node and the new
2086+# node.
2087 INTERFACE_UPDATE_NODE_NOTIFY = dedent("""\
2088 CREATE OR REPLACE FUNCTION nd_interface_update_notify()
2089 RETURNS trigger AS $$
2090@@ -208,11 +209,11 @@
2091 pnode RECORD;
2092 BEGIN
2093 IF OLD.node_id != NEW.node_id THEN
2094- SELECT system_id, installable, parent_id INTO node
2095+ SELECT system_id, node_type, parent_id INTO node
2096 FROM maasserver_node
2097 WHERE id = OLD.node_id;
2098
2099- IF node.installable THEN
2100+ IF node.node_type = %d THEN
2101 PERFORM pg_notify('node_update',CAST(node.system_id AS text));
2102 ELSIF node.parent_id IS NOT NULL THEN
2103 SELECT system_id INTO pnode
2104@@ -224,11 +225,11 @@
2105 END IF;
2106 END IF;
2107
2108- SELECT system_id, installable, parent_id INTO node
2109+ SELECT system_id, node_type, parent_id INTO node
2110 FROM maasserver_node
2111 WHERE id = NEW.node_id;
2112
2113- IF node.installable THEN
2114+ IF node.node_type = %d THEN
2115 PERFORM pg_notify('node_update',CAST(node.system_id AS text));
2116 ELSIF node.parent_id IS NOT NULL THEN
2117 SELECT system_id INTO pnode
2118@@ -246,18 +247,18 @@
2119
2120 # Procedure that is called when a physical or virtual block device is updated.
2121 # Sends a notify message for node_update or device_update depending on if the
2122-# node is installable.
2123+# node type is node.
2124 PHYSICAL_OR_VIRTUAL_BLOCK_DEVICE_NODE_NOTIFY = dedent("""\
2125 CREATE OR REPLACE FUNCTION %s() RETURNS trigger AS $$
2126 DECLARE
2127 node RECORD;
2128 BEGIN
2129- SELECT system_id, installable INTO node
2130+ SELECT system_id, node_type INTO node
2131 FROM maasserver_node, maasserver_blockdevice
2132 WHERE maasserver_node.id = maasserver_blockdevice.node_id
2133 AND maasserver_blockdevice.id = %s;
2134
2135- IF node.installable THEN
2136+ IF node.node_type = %d THEN
2137 PERFORM pg_notify('node_update',CAST(node.system_id AS text));
2138 END IF;
2139 RETURN NEW;
2140@@ -273,12 +274,12 @@
2141 DECLARE
2142 node RECORD;
2143 BEGIN
2144- SELECT system_id, installable INTO node
2145+ SELECT system_id, node_type INTO node
2146 FROM maasserver_node, maasserver_blockdevice
2147 WHERE maasserver_node.id = maasserver_blockdevice.node_id
2148 AND maasserver_blockdevice.id = %s;
2149
2150- IF node.installable THEN
2151+ IF node.node_type = %d THEN
2152 PERFORM pg_notify('node_update',CAST(node.system_id AS text));
2153 END IF;
2154 RETURN NEW;
2155@@ -293,7 +294,7 @@
2156 DECLARE
2157 node RECORD;
2158 BEGIN
2159- SELECT system_id, installable INTO node
2160+ SELECT system_id, node_type INTO node
2161 FROM maasserver_node,
2162 maasserver_blockdevice,
2163 maasserver_partitiontable
2164@@ -301,7 +302,7 @@
2165 AND maasserver_blockdevice.id = maasserver_partitiontable.block_device_id
2166 AND maasserver_partitiontable.id = %s;
2167
2168- IF node.installable THEN
2169+ IF node.node_type = %d THEN
2170 PERFORM pg_notify('node_update',CAST(node.system_id AS text));
2171 END IF;
2172 RETURN NEW;
2173@@ -316,7 +317,7 @@
2174 DECLARE
2175 node RECORD;
2176 BEGIN
2177- SELECT system_id, installable INTO node
2178+ SELECT system_id, node_type INTO node
2179 FROM maasserver_node,
2180 maasserver_blockdevice,
2181 maasserver_partition,
2182@@ -331,7 +332,7 @@
2183 maasserver_partition.partition_table_id
2184 AND maasserver_partition.id = %s));
2185
2186- IF node.installable THEN
2187+ IF node.node_type = %d THEN
2188 PERFORM pg_notify('node_update',CAST(node.system_id AS text));
2189 END IF;
2190 RETURN NEW;
2191@@ -346,7 +347,7 @@
2192 DECLARE
2193 node RECORD;
2194 BEGIN
2195- SELECT system_id, installable INTO node
2196+ SELECT system_id, node_type INTO node
2197 FROM maasserver_node,
2198 maasserver_blockdevice,
2199 maasserver_partition,
2200@@ -360,7 +361,7 @@
2201 AND (maasserver_filesystem.filesystem_group_id = %s
2202 OR maasserver_filesystem.cache_set_id = %s);
2203
2204- IF node.installable THEN
2205+ IF node.node_type = %d THEN
2206 PERFORM pg_notify('node_update',CAST(node.system_id AS text));
2207 END IF;
2208 RETURN NEW;
2209@@ -375,7 +376,7 @@
2210 DECLARE
2211 node RECORD;
2212 BEGIN
2213- SELECT system_id, installable INTO node
2214+ SELECT system_id, node_type INTO node
2215 FROM maasserver_node,
2216 maasserver_blockdevice,
2217 maasserver_partition,
2218@@ -388,7 +389,7 @@
2219 AND maasserver_partition.id = maasserver_filesystem.partition_id
2220 AND maasserver_filesystem.cache_set_id = %s;
2221
2222- IF node.installable THEN
2223+ IF node.node_type = %d THEN
2224 PERFORM pg_notify('node_update',CAST(node.system_id AS text));
2225 END IF;
2226 RETURN NEW;
2227@@ -405,7 +406,7 @@
2228 BEGIN
2229 FOR node IN (
2230 SELECT DISTINCT ON (maasserver_node.id)
2231- system_id, installable, parent_id
2232+ system_id, node_type, parent_id
2233 FROM
2234 maasserver_node,
2235 maasserver_subnet,
2236@@ -418,7 +419,7 @@
2237 AND ip_link.interface_id = maasserver_interface.id
2238 AND maasserver_node.id = maasserver_interface.node_id)
2239 LOOP
2240- IF node.installable THEN
2241+ IF node.node_type = %d THEN
2242 PERFORM pg_notify('node_update',CAST(node.system_id AS text));
2243 ELSIF node.parent_id IS NOT NULL THEN
2244 SELECT system_id INTO pnode
2245@@ -444,7 +445,7 @@
2246 BEGIN
2247 FOR node IN (
2248 SELECT DISTINCT ON (maasserver_node.id)
2249- system_id, installable, parent_id
2250+ system_id, node_type, parent_id
2251 FROM
2252 maasserver_node,
2253 maasserver_fabric,
2254@@ -455,7 +456,7 @@
2255 AND maasserver_node.id = maasserver_interface.node_id
2256 AND maasserver_vlan.id = maasserver_interface.vlan_id)
2257 LOOP
2258- IF node.installable THEN
2259+ IF node.node_type = %d THEN
2260 PERFORM pg_notify('node_update',CAST(node.system_id AS text));
2261 ELSIF node.parent_id IS NOT NULL THEN
2262 SELECT system_id INTO pnode
2263@@ -481,7 +482,7 @@
2264 BEGIN
2265 FOR node IN (
2266 SELECT DISTINCT ON (maasserver_node.id)
2267- system_id, installable, parent_id
2268+ system_id, node_type, parent_id
2269 FROM
2270 maasserver_node,
2271 maasserver_space,
2272@@ -496,7 +497,7 @@
2273 AND ip_link.interface_id = maasserver_interface.id
2274 AND maasserver_node.id = maasserver_interface.node_id)
2275 LOOP
2276- IF node.installable THEN
2277+ IF node.node_type = %d THEN
2278 PERFORM pg_notify('node_update',CAST(node.system_id AS text));
2279 ELSIF node.parent_id IS NOT NULL THEN
2280 SELECT system_id INTO pnode
2281@@ -522,13 +523,13 @@
2282 BEGIN
2283 FOR node IN (
2284 SELECT DISTINCT ON (maasserver_node.id)
2285- system_id, installable, parent_id
2286+ system_id, node_type, parent_id
2287 FROM maasserver_node, maasserver_interface, maasserver_vlan
2288 WHERE maasserver_vlan.id = %s
2289 AND maasserver_node.id = maasserver_interface.node_id
2290 AND maasserver_vlan.id = maasserver_interface.vlan_id)
2291 LOOP
2292- IF node.installable THEN
2293+ IF node.node_type = %d THEN
2294 PERFORM pg_notify('node_update',CAST(node.system_id AS text));
2295 ELSIF node.parent_id IS NOT NULL THEN
2296 SELECT system_id INTO pnode
2297@@ -555,7 +556,7 @@
2298 BEGIN
2299 FOR node IN (
2300 SELECT DISTINCT ON (maasserver_node.id)
2301- system_id, installable, parent_id
2302+ system_id, node_type, parent_id
2303 FROM
2304 maasserver_node,
2305 maasserver_interface,
2306@@ -564,7 +565,7 @@
2307 AND ip_link.interface_id = maasserver_interface.id
2308 AND maasserver_node.id = maasserver_interface.node_id)
2309 LOOP
2310- IF node.installable THEN
2311+ IF node.node_type = %d THEN
2312 PERFORM pg_notify('node_update',CAST(node.system_id AS text));
2313 ELSIF node.parent_id IS NOT NULL THEN
2314 SELECT system_id INTO pnode
2315@@ -638,11 +639,11 @@
2316 node RECORD;
2317 pnode RECORD;
2318 BEGIN
2319- SELECT system_id, installable, parent_id INTO node
2320+ SELECT system_id, node_type, parent_id INTO node
2321 FROM maasserver_node
2322 WHERE id = %s;
2323
2324- IF node.installable THEN
2325+ IF node.node_type = %d THEN
2326 PERFORM pg_notify('node_update',CAST(node.system_id AS text));
2327 ELSIF node.parent_id IS NOT NULL THEN
2328 SELECT system_id INTO pnode
2329@@ -655,7 +656,7 @@
2330 RETURN NEW;
2331 END;
2332 $$ LANGUAGE plpgsql;
2333- """ % (proc_name, node_id_relation))
2334+ """ % (proc_name, node_id_relation, NODE_TYPE.MACHINE))
2335
2336
2337 def register_trigger(table, procedure, event, params=None, when="after"):
2338@@ -699,7 +700,7 @@
2339 @transactional
2340 def register_all_triggers():
2341 """Register all triggers into the database."""
2342- # Node(installable) table
2343+ # Node where type is node table
2344 register_procedure(
2345 render_notification_procedure(
2346 'node_create_notify', 'node_create', 'NEW.system_id'))
2347@@ -711,13 +712,13 @@
2348 'node_delete_notify', 'node_delete', 'OLD.system_id'))
2349 register_trigger(
2350 "maasserver_node", "node_create_notify", "insert",
2351- {'NEW.installable': True})
2352+ {'NEW.node_type': NODE_TYPE.MACHINE})
2353 register_trigger(
2354 "maasserver_node", "node_update_notify", "update",
2355- {'NEW.installable': True})
2356+ {'NEW.node_type': NODE_TYPE.MACHINE})
2357 register_trigger(
2358 "maasserver_node", "node_delete_notify", "delete",
2359- {'OLD.installable': True})
2360+ {'OLD.node_type': NODE_TYPE.MACHINE})
2361
2362 # Node(device) table
2363 register_procedure(
2364@@ -731,13 +732,13 @@
2365 'device_delete_notify', 'device_delete', 'OLD'))
2366 register_trigger(
2367 "maasserver_node", "device_create_notify", "insert",
2368- {'NEW.installable': False})
2369+ {'NEW.node_type': NODE_TYPE.DEVICE})
2370 register_trigger(
2371 "maasserver_node", "device_update_notify", "update",
2372- {'NEW.installable': False})
2373+ {'NEW.node_type': NODE_TYPE.DEVICE})
2374 register_trigger(
2375 "maasserver_node", "device_delete_notify", "delete",
2376- {'OLD.installable': False})
2377+ {'OLD.node_type': NODE_TYPE.DEVICE})
2378
2379 # VLAN table
2380 register_procedure(
2381@@ -856,28 +857,32 @@
2382
2383 # Subnet node notifications
2384 register_procedure(
2385- SUBNET_NODE_NOTIFY % ('subnet_node_update_notify', 'NEW.id',))
2386+ SUBNET_NODE_NOTIFY % ('subnet_node_update_notify', 'NEW.id',
2387+ NODE_TYPE.MACHINE))
2388 register_trigger(
2389 "maasserver_subnet",
2390 "subnet_node_update_notify", "update")
2391
2392 # Fabric node notifications
2393 register_procedure(
2394- FABRIC_NODE_NOTIFY % ('fabric_node_update_notify', 'NEW.id',))
2395+ FABRIC_NODE_NOTIFY % ('fabric_node_update_notify', 'NEW.id',
2396+ NODE_TYPE.MACHINE))
2397 register_trigger(
2398 "maasserver_fabric",
2399 "fabric_node_update_notify", "update")
2400
2401 # Space node notifications
2402 register_procedure(
2403- SPACE_NODE_NOTIFY % ('space_node_update_notify', 'NEW.id',))
2404+ SPACE_NODE_NOTIFY % ('space_node_update_notify', 'NEW.id',
2405+ NODE_TYPE.MACHINE))
2406 register_trigger(
2407 "maasserver_space",
2408 "space_node_update_notify", "update")
2409
2410 # VLAN node notifications
2411 register_procedure(
2412- VLAN_NODE_NOTIFY % ('vlan_node_update_notify', 'NEW.id',))
2413+ VLAN_NODE_NOTIFY % ('vlan_node_update_notify', 'NEW.id',
2414+ NODE_TYPE.MACHINE))
2415 register_trigger(
2416 "maasserver_vlan",
2417 "vlan_node_update_notify", "update")
2418@@ -885,7 +890,7 @@
2419 # IP address node notifications
2420 register_procedure(
2421 STATIC_IP_ADDRESS_NODE_NOTIFY % (
2422- 'ipaddress_node_update_notify', 'NEW.id',))
2423+ 'ipaddress_node_update_notify', 'NEW.id', NODE_TYPE.MACHINE))
2424 register_trigger(
2425 "maasserver_staticipaddress",
2426 "ipaddress_node_update_notify", "update")
2427@@ -934,21 +939,17 @@
2428 # Node tag link table
2429 register_procedure(
2430 NODE_TAG_NOTIFY % (
2431- 'node_device_tag_link_notify',
2432- 'NEW.node_id',
2433- ))
2434+ 'node_device_tag_link_notify', 'NEW.node_id', NODE_TYPE.MACHINE))
2435 register_procedure(
2436 NODE_TAG_NOTIFY % (
2437- 'node_device_tag_unlink_notify',
2438- 'OLD.node_id',
2439- ))
2440+ 'node_device_tag_unlink_notify', 'OLD.node_id', NODE_TYPE.MACHINE))
2441 register_trigger(
2442 "maasserver_node_tags", "node_device_tag_link_notify", "insert")
2443 register_trigger(
2444 "maasserver_node_tags", "node_device_tag_unlink_notify", "delete")
2445
2446 # Tag table, update to linked nodes.
2447- register_procedure(TAG_NODES_NOTIFY)
2448+ register_procedure(TAG_NODES_NOTIFY % NODE_TYPE.MACHINE)
2449 register_trigger(
2450 "maasserver_tag", "tag_update_node_device_notify", "update")
2451
2452@@ -987,21 +988,19 @@
2453 "maasserver_event", "event_delete_notify", "delete")
2454
2455 # Events table, update to linked node.
2456- register_procedure(EVENT_NODE_NOTIFY)
2457+ register_procedure(EVENT_NODE_NOTIFY % NODE_TYPE.MACHINE)
2458 register_trigger(
2459 "maasserver_event", "event_create_node_device_notify", "insert")
2460
2461 # MAC static ip address table, update to linked node.
2462 register_procedure(
2463 INTERFACE_IP_ADDRESS_NODE_NOTIFY % (
2464- 'nd_sipaddress_link_notify',
2465- 'NEW.interface_id',
2466- ))
2467+ 'nd_sipaddress_link_notify', 'NEW.interface_id',
2468+ NODE_TYPE.MACHINE))
2469 register_procedure(
2470 INTERFACE_IP_ADDRESS_NODE_NOTIFY % (
2471- 'nd_sipaddress_unlink_notify',
2472- 'OLD.interface_id',
2473- ))
2474+ 'nd_sipaddress_unlink_notify', 'OLD.interface_id',
2475+ NODE_TYPE.MACHINE))
2476 register_trigger(
2477 "maasserver_interface_ip_addresses",
2478 "nd_sipaddress_link_notify", "insert")
2479@@ -1030,7 +1029,8 @@
2480 register_procedure(
2481 render_node_related_notification_procedure(
2482 'nd_interface_unlink_notify', 'OLD.node_id'))
2483- register_procedure(INTERFACE_UPDATE_NODE_NOTIFY)
2484+ register_procedure(
2485+ INTERFACE_UPDATE_NODE_NOTIFY % (NODE_TYPE.MACHINE, NODE_TYPE.MACHINE))
2486 register_trigger(
2487 "maasserver_interface",
2488 "nd_interface_link_notify", "insert")
2489@@ -1053,10 +1053,12 @@
2490 'nd_blockdevice_unlink_notify', 'OLD.node_id'))
2491 register_procedure(
2492 PHYSICAL_OR_VIRTUAL_BLOCK_DEVICE_NODE_NOTIFY % (
2493- 'nd_physblockdevice_update_notify', 'NEW.blockdevice_ptr_id'))
2494+ 'nd_physblockdevice_update_notify', 'NEW.blockdevice_ptr_id',
2495+ NODE_TYPE.MACHINE))
2496 register_procedure(
2497 PHYSICAL_OR_VIRTUAL_BLOCK_DEVICE_NODE_NOTIFY % (
2498- 'nd_virtblockdevice_update_notify', 'NEW.blockdevice_ptr_id'))
2499+ 'nd_virtblockdevice_update_notify', 'NEW.blockdevice_ptr_id',
2500+ NODE_TYPE.MACHINE))
2501 register_trigger(
2502 "maasserver_blockdevice",
2503 "nd_blockdevice_link_notify", "insert")
2504@@ -1076,13 +1078,17 @@
2505 # Partition table, update to linked user.
2506 register_procedure(
2507 PARTITIONTABLE_NODE_NOTIFY % (
2508- 'nd_partitiontable_link_notify', 'NEW.block_device_id'))
2509- register_procedure(
2510- PARTITIONTABLE_NODE_NOTIFY % (
2511- 'nd_partitiontable_update_notify', 'NEW.block_device_id'))
2512- register_procedure(
2513- PARTITIONTABLE_NODE_NOTIFY % (
2514- 'nd_partitiontable_unlink_notify', 'OLD.block_device_id'))
2515+ 'nd_partitiontable_link_notify', 'NEW.block_device_id',
2516+ NODE_TYPE.MACHINE))
2517+ register_procedure(
2518+ PARTITIONTABLE_NODE_NOTIFY % (
2519+ 'nd_partitiontable_update_notify',
2520+ 'NEW.block_device_id',
2521+ NODE_TYPE.MACHINE))
2522+ register_procedure(
2523+ PARTITIONTABLE_NODE_NOTIFY % (
2524+ 'nd_partitiontable_unlink_notify', 'OLD.block_device_id',
2525+ NODE_TYPE.MACHINE))
2526 register_trigger(
2527 "maasserver_partitiontable",
2528 "nd_partitiontable_link_notify", "insert")
2529@@ -1096,13 +1102,16 @@
2530 # Partition, update to linked user.
2531 register_procedure(
2532 PARTITION_NODE_NOTIFY % (
2533- 'nd_partition_link_notify', 'NEW.partition_table_id'))
2534- register_procedure(
2535- PARTITION_NODE_NOTIFY % (
2536- 'nd_partition_update_notify', 'NEW.partition_table_id'))
2537- register_procedure(
2538- PARTITION_NODE_NOTIFY % (
2539- 'nd_partition_unlink_notify', 'OLD.partition_table_id'))
2540+ 'nd_partition_link_notify', 'NEW.partition_table_id',
2541+ NODE_TYPE.MACHINE))
2542+ register_procedure(
2543+ PARTITION_NODE_NOTIFY % (
2544+ 'nd_partition_update_notify', 'NEW.partition_table_id',
2545+ NODE_TYPE.MACHINE))
2546+ register_procedure(
2547+ PARTITION_NODE_NOTIFY % (
2548+ 'nd_partition_unlink_notify', 'OLD.partition_table_id',
2549+ NODE_TYPE.MACHINE))
2550 register_trigger(
2551 "maasserver_partition",
2552 "nd_partition_link_notify", "insert")
2553@@ -1117,15 +1126,15 @@
2554 register_procedure(
2555 FILESYSTEM_NODE_NOTIFY % (
2556 'nd_filesystem_link_notify', 'NEW.block_device_id',
2557- 'NEW.partition_id'))
2558+ 'NEW.partition_id', NODE_TYPE.MACHINE))
2559 register_procedure(
2560 FILESYSTEM_NODE_NOTIFY % (
2561 'nd_filesystem_update_notify', 'NEW.block_device_id',
2562- 'NEW.partition_id'))
2563+ 'NEW.partition_id', NODE_TYPE.MACHINE))
2564 register_procedure(
2565 FILESYSTEM_NODE_NOTIFY % (
2566 'nd_filesystem_unlink_notify', 'OLD.block_device_id',
2567- 'OLD.partition_id'))
2568+ 'OLD.partition_id', NODE_TYPE.MACHINE))
2569 register_trigger(
2570 "maasserver_filesystem",
2571 "nd_filesystem_link_notify", "insert")
2572@@ -1139,13 +1148,16 @@
2573 # Filesystemgroup, update to linked user.
2574 register_procedure(
2575 FILESYSTEMGROUP_NODE_NOTIFY % (
2576- 'nd_filesystemgroup_link_notify', 'NEW.id', 'NEW.cache_set_id'))
2577- register_procedure(
2578- FILESYSTEMGROUP_NODE_NOTIFY % (
2579- 'nd_filesystemgroup_update_notify', 'NEW.id', 'NEW.cache_set_id'))
2580- register_procedure(
2581- FILESYSTEMGROUP_NODE_NOTIFY % (
2582- 'nd_filesystemgroup_unlink_notify', 'OLD.id', 'OLD.cache_set_id'))
2583+ 'nd_filesystemgroup_link_notify', 'NEW.id', 'NEW.cache_set_id',
2584+ NODE_TYPE.MACHINE))
2585+ register_procedure(
2586+ FILESYSTEMGROUP_NODE_NOTIFY % (
2587+ 'nd_filesystemgroup_update_notify', 'NEW.id', 'NEW.cache_set_id',
2588+ NODE_TYPE.MACHINE))
2589+ register_procedure(
2590+ FILESYSTEMGROUP_NODE_NOTIFY % (
2591+ 'nd_filesystemgroup_unlink_notify', 'OLD.id', 'OLD.cache_set_id',
2592+ NODE_TYPE.MACHINE))
2593 register_trigger(
2594 "maasserver_filesystemgroup",
2595 "nd_filesystemgroup_link_notify", "insert")
2596@@ -1159,13 +1171,13 @@
2597 # Cacheset, update to linked user.
2598 register_procedure(
2599 CACHESET_NODE_NOTIFY % (
2600- 'nd_cacheset_link_notify', 'NEW.id'))
2601- register_procedure(
2602- CACHESET_NODE_NOTIFY % (
2603- 'nd_cacheset_update_notify', 'NEW.id'))
2604- register_procedure(
2605- CACHESET_NODE_NOTIFY % (
2606- 'nd_cacheset_unlink_notify', 'OLD.id'))
2607+ 'nd_cacheset_link_notify', 'NEW.id', NODE_TYPE.MACHINE))
2608+ register_procedure(
2609+ CACHESET_NODE_NOTIFY % (
2610+ 'nd_cacheset_update_notify', 'NEW.id', NODE_TYPE.MACHINE))
2611+ register_procedure(
2612+ CACHESET_NODE_NOTIFY % (
2613+ 'nd_cacheset_unlink_notify', 'OLD.id', NODE_TYPE.MACHINE))
2614 register_trigger(
2615 "maasserver_cacheset",
2616 "nd_cacheset_link_notify", "insert")
2617
2618=== modified file 'src/maasserver/websockets/handlers/device.py'
2619--- src/maasserver/websockets/handlers/device.py 2015-12-01 18:12:59 +0000
2620+++ src/maasserver/websockets/handlers/device.py 2015-12-18 15:12:10 +0000
2621@@ -11,6 +11,7 @@
2622 from maasserver.enum import (
2623 IPADDRESS_TYPE,
2624 NODE_PERMISSION,
2625+ NODE_TYPE,
2626 )
2627 from maasserver.exceptions import NodeActionError
2628 from maasserver.forms import (
2629@@ -87,7 +88,7 @@
2630
2631 class Meta:
2632 queryset = (
2633- Device.devices.filter(installable=False, parent=None)
2634+ Device.devices.filter(node_type=NODE_TYPE.DEVICE, parent=None)
2635 .select_related('nodegroup', 'owner')
2636 .prefetch_related('interface_set__ip_addresses__subnet')
2637 .prefetch_related('nodegroup__nodegroupinterface_set')
2638@@ -98,7 +99,7 @@
2639 allowed_methods = ['list', 'get', 'set_active', 'create', 'action']
2640 exclude = [
2641 "id",
2642- "installable",
2643+ "type",
2644 "boot_interface",
2645 "boot_cluster_ip",
2646 "boot_disk",
2647
2648=== modified file 'src/maasserver/websockets/handlers/general.py'
2649--- src/maasserver/websockets/handlers/general.py 2015-12-01 18:12:59 +0000
2650+++ src/maasserver/websockets/handlers/general.py 2015-12-18 15:12:10 +0000
2651@@ -94,19 +94,19 @@
2652 actions = dict()
2653 for name, action in ACTIONS_DICT.items():
2654 permission = action.permission
2655- if action.installable_permission is not None:
2656- permission = action.installable_permission
2657+ if action.node_permission is not None:
2658+ permission = action.node_permission
2659 if permission != NODE_PERMISSION.ADMIN:
2660 actions[name] = action
2661 return self.dehydrate_actions(actions)
2662
2663 def device_actions(self, params):
2664 """Return all possible device actions."""
2665- # Remove the actions that can only be performed on installable nodes.
2666+ # Remove the actions that can only be performed on nodes.
2667 actions = {
2668 name: action
2669 for name, action in ACTIONS_DICT.items()
2670- if not action.installable_only
2671+ if not action.node_only
2672 }
2673 return self.dehydrate_actions(actions)
2674
2675
2676=== modified file 'src/maasserver/websockets/handlers/node.py'
2677--- src/maasserver/websockets/handlers/node.py 2015-12-01 18:12:59 +0000
2678+++ src/maasserver/websockets/handlers/node.py 2015-12-18 15:12:10 +0000
2679@@ -19,6 +19,7 @@
2680 IPADDRESS_TYPE,
2681 NODE_PERMISSION,
2682 NODE_STATUS,
2683+ NODE_TYPE,
2684 )
2685 from maasserver.exceptions import NodeActionError
2686 from maasserver.forms import (
2687@@ -106,7 +107,7 @@
2688
2689 class Meta:
2690 queryset = (
2691- Node.nodes.filter(installable=True)
2692+ Node.nodes.filter(node_type=NODE_TYPE.MACHINE)
2693 .select_related('nodegroup', 'boot_interface', 'owner')
2694 .prefetch_related(
2695 'interface_set__ip_addresses__subnet__vlan__fabric')
2696@@ -151,7 +152,6 @@
2697 ]
2698 form = AdminNodeWithMACAddressesForm
2699 exclude = [
2700- "installable",
2701 "parent",
2702 "boot_interface",
2703 "boot_cluster_ip",
2704@@ -1188,7 +1188,7 @@
2705 @transactional
2706 def get_node_cluster_and_power_info():
2707 obj = self.get_object(params)
2708- if obj.installable:
2709+ if obj.power_type is not None:
2710 node_info = obj.system_id, obj.hostname
2711 nodegroup_info = obj.nodegroup.cluster_name, obj.nodegroup.uuid
2712 try:
2713@@ -1199,8 +1199,8 @@
2714 return node_info, nodegroup_info, power_info
2715 else:
2716 raise HandlerError(
2717- "%s: Unable to query power state; not an "
2718- "installable node" % obj.hostname)
2719+ "%s: Unable to query power state; no power state defined"
2720+ % obj.hostname)
2721
2722 @transactional
2723 def update_power_state(state):
2724
2725=== modified file 'src/maasserver/websockets/handlers/tests/test_device.py'
2726--- src/maasserver/websockets/handlers/tests/test_device.py 2015-12-02 20:43:30 +0000
2727+++ src/maasserver/websockets/handlers/tests/test_device.py 2015-12-18 15:12:10 +0000
2728@@ -7,6 +7,7 @@
2729
2730 from maasserver.enum import (
2731 IPADDRESS_TYPE,
2732+ NODE_TYPE,
2733 NODEGROUP_STATUS,
2734 NODEGROUPINTERFACE_MANAGEMENT,
2735 )
2736@@ -107,6 +108,7 @@
2737 tag.name
2738 for tag in node.tags.all()
2739 ],
2740+ "node_type": node.node_type,
2741 "updated": dehydrate_datetime(node.updated),
2742 "zone": {
2743 "id": node.zone.id,
2744@@ -140,7 +142,7 @@
2745 if owner is None:
2746 owner = factory.make_User()
2747 device = factory.make_Node(
2748- nodegroup=nodegroup, installable=False,
2749+ nodegroup=nodegroup, node_type=NODE_TYPE.DEVICE,
2750 interface=True, owner=owner)
2751 interface = device.get_boot_interface()
2752 if ip_assignment == DEVICE_IP_ASSIGNMENT.EXTERNAL:
2753@@ -483,7 +485,7 @@
2754
2755 def test_action_performs_action(self):
2756 user = factory.make_User()
2757- device = factory.make_Node(owner=user, installable=False)
2758+ device = factory.make_Node(owner=user, node_type=NODE_TYPE.DEVICE)
2759 handler = DeviceHandler(user, {})
2760 handler.action({"system_id": device.system_id, "action": "delete"})
2761 self.assertIsNone(reload_object(device))
2762
2763=== modified file 'src/maasserver/websockets/handlers/tests/test_general.py'
2764--- src/maasserver/websockets/handlers/tests/test_general.py 2015-12-01 18:12:59 +0000
2765+++ src/maasserver/websockets/handlers/tests/test_general.py 2015-12-18 15:12:10 +0000
2766@@ -115,8 +115,8 @@
2767 actions_expected = dict()
2768 for name, action in ACTIONS_DICT.items():
2769 permission = action.permission
2770- if action.installable_permission is not None:
2771- permission = action.installable_permission
2772+ if action.node_permission is not None:
2773+ permission = action.node_permission
2774 if permission != NODE_PERMISSION.ADMIN:
2775 actions_expected[name] = action
2776 actions_expected = self.dehydrate_actions(actions_expected)
2777@@ -127,7 +127,7 @@
2778 actions_expected = self.dehydrate_actions({
2779 name: action
2780 for name, action in ACTIONS_DICT.items()
2781- if not action.installable_only
2782+ if not action.node_only
2783 })
2784 self.assertItemsEqual(actions_expected, handler.device_actions({}))
2785
2786
2787=== modified file 'src/maasserver/websockets/handlers/tests/test_node.py'
2788--- src/maasserver/websockets/handlers/tests/test_node.py 2015-12-02 20:43:30 +0000
2789+++ src/maasserver/websockets/handlers/tests/test_node.py 2015-12-18 15:12:10 +0000
2790@@ -23,6 +23,7 @@
2791 INTERFACE_TYPE,
2792 IPADDRESS_TYPE,
2793 NODE_STATUS,
2794+ NODE_TYPE,
2795 )
2796 from maasserver.exceptions import NodeActionError
2797 from maasserver.forms import AdminNodeWithMACAddressesForm
2798@@ -213,6 +214,7 @@
2799 "module": driver["module"] if "module" in driver else "",
2800 "comment": driver["comment"] if "comment" in driver else "",
2801 },
2802+ "node_type": node.node_type,
2803 "updated": dehydrate_datetime(node.updated),
2804 "zone": handler.dehydrate_zone(node.zone),
2805 }
2806@@ -248,7 +250,7 @@
2807 # Make some devices.
2808 for _ in range(3):
2809 factory.make_Node(
2810- installable=False, parent=node, interface=True)
2811+ node_type=NODE_TYPE.DEVICE, parent=node, interface=True)
2812
2813 def test_dehydrate_owner_empty_when_None(self):
2814 owner = factory.make_User()
2815@@ -333,7 +335,7 @@
2816 owner = factory.make_User()
2817 node = factory.make_Node(owner=owner)
2818 handler = NodeHandler(owner, {})
2819- device = factory.make_Node(installable=False, parent=node)
2820+ device = factory.make_Node(node_type=NODE_TYPE.DEVICE, parent=node)
2821 interface = factory.make_Interface(
2822 INTERFACE_TYPE.PHYSICAL, node=device)
2823 self.assertEqual({
2824@@ -831,7 +833,7 @@
2825 # Make some devices.
2826 for _ in range(3):
2827 factory.make_Node(
2828- installable=False, parent=node, interface=True)
2829+ node_type=NODE_TYPE.DEVICE, parent=node, interface=True)
2830
2831 self.patch_autospec(interface_module, "update_host_maps")
2832 boot_interface = node.get_boot_interface()
2833@@ -856,7 +858,7 @@
2834 owner = factory.make_User()
2835 handler = NodeHandler(owner, {})
2836 # Create a device.
2837- factory.make_Node(owner=owner, installable=False)
2838+ factory.make_Node(owner=owner, node_type=NODE_TYPE.DEVICE)
2839 node = factory.make_Node(owner=owner)
2840 self.assertItemsEqual(
2841 [self.dehydrate_node(node, handler, for_list=True)],