Merge ~ltrager/maas:node_device_websocket into maas:master
- Git
- lp:~ltrager/maas
- node_device_websocket
- Merge into master
Status: | Merged |
---|---|
Approved by: | Adam Collard |
Approved revision: | d6d84b1ebcbb150d596d9d4dff11ddbfe0a18e89 |
Merge reported by: | MAAS Lander |
Merged at revision: | not available |
Proposed branch: | ~ltrager/maas:node_device_websocket |
Merge into: | maas:master |
Prerequisite: | ~ltrager/maas:node_device_api |
Diff against target: |
366 lines (+220/-6) 10 files modified
src/maasserver/triggers/testing.py (+17/-1) src/maasserver/triggers/tests/test_init.py (+3/-0) src/maasserver/triggers/tests/test_websocket_listener.py (+63/-0) src/maasserver/triggers/websocket.py (+19/-1) src/maasserver/websockets/handlers/__init__.py (+3/-2) src/maasserver/websockets/handlers/node.py (+1/-1) src/maasserver/websockets/handlers/node_device.py (+51/-0) src/maasserver/websockets/handlers/tests/test_machine.py (+10/-1) src/maasserver/websockets/handlers/tests/test_node_device.py (+51/-0) src/maasserver/websockets/tests/test_protocol.py (+2/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
MAAS Lander | Approve | ||
Alberto Donato (community) | Approve | ||
Review via email: mp+395409@code.launchpad.net |
Commit message
Add NodeDevice websocket
Description of the change
- 525610a... by Lee Trager
-
Merge branch 'master' into node_device_model
- b48316d... by Lee Trager
-
ack fix
- 2fbf073... by Lee Trager
-
Merge branch 'node_device_model' into process_
node_device_ data - 4d8aa9f... by Lee Trager
-
Fix merge mistake
- 69c462f... by Lee Trager
-
Merge branch 'process_
node_device_ data' into node_device_api - f69a752... by Lee Trager
-
Merge branch 'node_device_api' into node_device_
websocket
MAAS Lander (maas-lander) wrote : | # |
UNIT TESTS
-b node_device_
STATUS: FAILED
LOG: http://
COMMIT: f69a7522c82a1e5
- 72cf97b... by Lee Trager
-
Merge branch 'master' into process_
node_device_ data - 1d81711... by Lee Trager
-
Merge branch 'process_
node_device_ data' into node_device_api - 174a1d0... by Lee Trager
-
Merge branch 'node_device_api' into node_device_
websocket - 2b01786... by Lee Trager
-
Fix failing test
MAAS Lander (maas-lander) wrote : | # |
UNIT TESTS
-b node_device_
STATUS: FAILED
LOG: http://
COMMIT: 2b0178667029978
- ad87d83... by Lee Trager
-
Merge branch 'master' into process_
node_device_ data - 917084b... by Lee Trager
-
adam-collard fixes
- f7b6424... by Lee Trager
-
Merge branch 'process_
node_device_ data' into node_device_api - d6d84b1... by Lee Trager
-
Merge branch 'node_device_api' into node_device_
websocket
MAAS Lander (maas-lander) wrote : | # |
UNIT TESTS
-b node_device_
STATUS: SUCCESS
COMMIT: d6d84b1ebcbb150
Preview Diff
1 | diff --git a/src/maasserver/triggers/testing.py b/src/maasserver/triggers/testing.py |
2 | index 0a52dbd..5525281 100644 |
3 | --- a/src/maasserver/triggers/testing.py |
4 | +++ b/src/maasserver/triggers/testing.py |
5 | @@ -1,4 +1,4 @@ |
6 | -# Copyright 2016 Canonical Ltd. This software is licensed under the |
7 | +# Copyright 2016-2020 Canonical Ltd. This software is licensed under the |
8 | # GNU Affero General Public License version 3 (see the file LICENSE). |
9 | |
10 | """Helper class for all tests using the `PostgresListenerService` under |
11 | @@ -29,6 +29,7 @@ from maasserver.models.filesystemgroup import FilesystemGroup |
12 | from maasserver.models.interface import Interface |
13 | from maasserver.models.iprange import IPRange |
14 | from maasserver.models.node import Node, RackController, RegionController |
15 | +from maasserver.models.nodedevice import NodeDevice |
16 | from maasserver.models.nodemetadata import NodeMetadata |
17 | from maasserver.models.packagerepository import PackageRepository |
18 | from maasserver.models.partition import Partition |
19 | @@ -827,6 +828,21 @@ class TransactionalHelpersMixin: |
20 | config.value = value |
21 | config.save() |
22 | |
23 | + @transactional |
24 | + def create_node_device(self, params=None): |
25 | + if params is None: |
26 | + params = {} |
27 | + return factory.make_NodeDevice(**params) |
28 | + |
29 | + @transactional |
30 | + def update_node_device(self, id, params, **kwargs): |
31 | + return apply_update_to_model(NodeDevice, id, params, **kwargs) |
32 | + |
33 | + @transactional |
34 | + def delete_node_device(self, id): |
35 | + node_device = NodeDevice.objects.get(id=id) |
36 | + node_device.delete() |
37 | + |
38 | |
39 | class DNSHelpersMixin: |
40 | """Helper to get the zone serial and to assert it was incremented.""" |
41 | diff --git a/src/maasserver/triggers/tests/test_init.py b/src/maasserver/triggers/tests/test_init.py |
42 | index 165d325..93e749d 100644 |
43 | --- a/src/maasserver/triggers/tests/test_init.py |
44 | +++ b/src/maasserver/triggers/tests/test_init.py |
45 | @@ -187,6 +187,9 @@ class TestTriggersUsed(MAASServerTestCase): |
46 | "neighbour_neighbour_create_notify", |
47 | "neighbour_neighbour_delete_notify", |
48 | "neighbour_neighbour_update_notify", |
49 | + "nodedevice_nodedevice_create_notify", |
50 | + "nodedevice_nodedevice_delete_notify", |
51 | + "nodedevice_nodedevice_update_notify", |
52 | "node_device_create_notify", |
53 | "node_device_delete_notify", |
54 | "node_device_update_notify", |
55 | diff --git a/src/maasserver/triggers/tests/test_websocket_listener.py b/src/maasserver/triggers/tests/test_websocket_listener.py |
56 | index 8589e21..9b1f535 100644 |
57 | --- a/src/maasserver/triggers/tests/test_websocket_listener.py |
58 | +++ b/src/maasserver/triggers/tests/test_websocket_listener.py |
59 | @@ -5132,3 +5132,66 @@ class TestScriptListener( |
60 | self.assertEqual(("delete", "%s" % script.id), dv.value) |
61 | finally: |
62 | yield listener.stopService() |
63 | + |
64 | + |
65 | +class TestNodeDeviceListener( |
66 | + MAASTransactionServerTestCase, TransactionalHelpersMixin |
67 | +): |
68 | + @wait_for_reactor |
69 | + @inlineCallbacks |
70 | + def test_calls_handler_on_create_notification(self): |
71 | + yield deferToDatabase(register_websocket_triggers) |
72 | + node = yield deferToDatabase(self.create_node) |
73 | + listener = self.make_listener_without_delay() |
74 | + dv = DeferredValue() |
75 | + listener.register("nodedevice", lambda *args: dv.set(args)) |
76 | + yield listener.startService() |
77 | + try: |
78 | + node_device = yield deferToDatabase( |
79 | + self.create_node_device, {"node": node} |
80 | + ) |
81 | + yield dv.get(timeout=2) |
82 | + self.assertEqual(("create", "%s" % node_device.id), dv.value) |
83 | + finally: |
84 | + yield listener.stopService() |
85 | + |
86 | + @wait_for_reactor |
87 | + @inlineCallbacks |
88 | + def test_calls_handler_on_update_notification(self): |
89 | + yield deferToDatabase(register_websocket_triggers) |
90 | + listener = self.make_listener_without_delay() |
91 | + dv = DeferredValue() |
92 | + listener.register("nodedevice", lambda *args: dv.set(args)) |
93 | + node_device = yield deferToDatabase(self.create_node_device) |
94 | + |
95 | + yield listener.startService() |
96 | + try: |
97 | + yield deferToDatabase( |
98 | + self.update_node_device, |
99 | + node_device.id, |
100 | + { |
101 | + "commissioning_driver": factory.make_name( |
102 | + "commissioning_driver" |
103 | + ) |
104 | + }, |
105 | + ) |
106 | + yield dv.get(timeout=2) |
107 | + self.assertEqual(("update", "%s" % node_device.id), dv.value) |
108 | + finally: |
109 | + yield listener.stopService() |
110 | + |
111 | + @wait_for_reactor |
112 | + @inlineCallbacks |
113 | + def test_calls_handler_on_delete_notification(self): |
114 | + yield deferToDatabase(register_websocket_triggers) |
115 | + listener = self.make_listener_without_delay() |
116 | + dv = DeferredValue() |
117 | + listener.register("nodedevice", lambda *args: dv.set(args)) |
118 | + node_device = yield deferToDatabase(self.create_node_device) |
119 | + yield listener.startService() |
120 | + try: |
121 | + yield deferToDatabase(self.delete_node_device, node_device.id) |
122 | + yield dv.get(timeout=2) |
123 | + self.assertEqual(("delete", "%s" % node_device.id), dv.value) |
124 | + finally: |
125 | + yield listener.stopService() |
126 | diff --git a/src/maasserver/triggers/websocket.py b/src/maasserver/triggers/websocket.py |
127 | index bbd0861..ac2f9e2 100644 |
128 | --- a/src/maasserver/triggers/websocket.py |
129 | +++ b/src/maasserver/triggers/websocket.py |
130 | @@ -1,4 +1,4 @@ |
131 | -# Copyright 2015-2018 Canonical Ltd. This software is licensed under the |
132 | +# Copyright 2015-2020 Canonical Ltd. This software is licensed under the |
133 | # GNU Affero General Public License version 3 (see the file LICENSE). |
134 | |
135 | """ |
136 | @@ -2724,3 +2724,21 @@ def register_websocket_triggers(): |
137 | ) |
138 | ) |
139 | register_triggers("metadataserver_script", "script") |
140 | + |
141 | + # NodeDevice table |
142 | + register_procedure( |
143 | + render_notification_procedure( |
144 | + "nodedevice_create_notify", "nodedevice_create", "NEW.id" |
145 | + ) |
146 | + ) |
147 | + register_procedure( |
148 | + render_notification_procedure( |
149 | + "nodedevice_update_notify", "nodedevice_update", "NEW.id" |
150 | + ) |
151 | + ) |
152 | + register_procedure( |
153 | + render_notification_procedure( |
154 | + "nodedevice_delete_notify", "nodedevice_delete", "OLD.id" |
155 | + ) |
156 | + ) |
157 | + register_triggers("maasserver_nodedevice", "nodedevice") |
158 | diff --git a/src/maasserver/websockets/handlers/__init__.py b/src/maasserver/websockets/handlers/__init__.py |
159 | index 87901f8..1ae365c 100644 |
160 | --- a/src/maasserver/websockets/handlers/__init__.py |
161 | +++ b/src/maasserver/websockets/handlers/__init__.py |
162 | @@ -1,4 +1,4 @@ |
163 | -# Copyright 2015-2017 Canonical Ltd. This software is licensed under the |
164 | +# Copyright 2015-2020 Canonical Ltd. This software is licensed under the |
165 | # GNU Affero General Public License version 3 (see the file LICENSE). |
166 | |
167 | """Handlers for the WebSocket connections.""" |
168 | @@ -19,7 +19,7 @@ __all__ = [ |
169 | "IPRangeHandler", |
170 | "IPRangeHandler", |
171 | "MachineHandler", |
172 | - "NodeResultHandler", |
173 | + "NodeDeviceHandler", |
174 | "NodeResultHandler", |
175 | "NotificationHandler", |
176 | "PackageRepositoryHandler", |
177 | @@ -52,6 +52,7 @@ from maasserver.websockets.handlers.fabric import FabricHandler |
178 | from maasserver.websockets.handlers.general import GeneralHandler |
179 | from maasserver.websockets.handlers.iprange import IPRangeHandler |
180 | from maasserver.websockets.handlers.machine import MachineHandler |
181 | +from maasserver.websockets.handlers.node_device import NodeDeviceHandler |
182 | from maasserver.websockets.handlers.node_result import NodeResultHandler |
183 | from maasserver.websockets.handlers.notification import NotificationHandler |
184 | from maasserver.websockets.handlers.packagerepository import ( |
185 | diff --git a/src/maasserver/websockets/handlers/node.py b/src/maasserver/websockets/handlers/node.py |
186 | index 48b4e38..bca7d2f 100644 |
187 | --- a/src/maasserver/websockets/handlers/node.py |
188 | +++ b/src/maasserver/websockets/handlers/node.py |
189 | @@ -138,7 +138,7 @@ class NodeHandler(TimestampedModelHandler): |
190 | def dehydrate_numanode(self, numa_node): |
191 | details = { |
192 | attr: getattr(numa_node, attr) |
193 | - for attr in ("index", "memory", "cores") |
194 | + for attr in ("id", "index", "memory", "cores") |
195 | } |
196 | details["hugepages_set"] = [ |
197 | self.dehydrate_hugepages(hugepages) |
198 | diff --git a/src/maasserver/websockets/handlers/node_device.py b/src/maasserver/websockets/handlers/node_device.py |
199 | new file mode 100644 |
200 | index 0000000..c69409d |
201 | --- /dev/null |
202 | +++ b/src/maasserver/websockets/handlers/node_device.py |
203 | @@ -0,0 +1,51 @@ |
204 | +# Copyright 2020 Canonical Ltd. This software is licensed under the |
205 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
206 | + |
207 | +"""The Script handler for the WebSocket connection.""" |
208 | + |
209 | +from operator import attrgetter |
210 | + |
211 | +from maasserver.models import NodeDevice |
212 | +from maasserver.websockets.base import HandlerPKError |
213 | +from maasserver.websockets.handlers.timestampedmodel import ( |
214 | + TimestampedModelHandler, |
215 | +) |
216 | + |
217 | + |
218 | +class NodeDeviceHandler(TimestampedModelHandler): |
219 | + class Meta: |
220 | + queryset = NodeDevice.objects.all() |
221 | + pk = "id" |
222 | + allowed_methods = ["list", "delete"] |
223 | + listen_channels = ["nodedevice"] |
224 | + |
225 | + def dehydrate(self, obj, data, for_list=False): |
226 | + # When NodeDevices are loaded in the UI the client has already received |
227 | + # the keys below. Instead of reprocessing them make it clear the handler |
228 | + # is only returning the ids, not values, |
229 | + for key in [ |
230 | + "physical_blockdevice", |
231 | + "physical_interface", |
232 | + "numa_node", |
233 | + "node", |
234 | + ]: |
235 | + id = data.pop(key) |
236 | + data[f"{key}_id"] = id |
237 | + return data |
238 | + |
239 | + def list(self, params): |
240 | + """List NodeDevice objects. |
241 | + |
242 | + :param system_id: `Node.system_id` for the NodeDevices. |
243 | + """ |
244 | + if "system_id" not in params: |
245 | + raise HandlerPKError("Missing system_id in params") |
246 | + system_id = params["system_id"] |
247 | + |
248 | + qs = self.get_queryset(for_list=True) |
249 | + qs = qs.filter(node__system_id=system_id) |
250 | + |
251 | + objs = list(qs) |
252 | + getpk = attrgetter(self._meta.pk) |
253 | + self.cache["loaded_pks"].update(getpk(obj) for obj in objs) |
254 | + return [self.full_dehydrate(obj, for_list=True) for obj in objs] |
255 | diff --git a/src/maasserver/websockets/handlers/tests/test_machine.py b/src/maasserver/websockets/handlers/tests/test_machine.py |
256 | index 6ce5614..62cd7d6 100644 |
257 | --- a/src/maasserver/websockets/handlers/tests/test_machine.py |
258 | +++ b/src/maasserver/websockets/handlers/tests/test_machine.py |
259 | @@ -2088,20 +2088,29 @@ class TestMachineHandler(MAASServerTestCase): |
260 | self.assertEqual( |
261 | result["numa_nodes"], |
262 | [ |
263 | - {"index": 0, "memory": 0, "cores": [], "hugepages_set": []}, |
264 | { |
265 | + "id": numa_node.id - 3, |
266 | + "index": 0, |
267 | + "memory": 0, |
268 | + "cores": [], |
269 | + "hugepages_set": [], |
270 | + }, |
271 | + { |
272 | + "id": numa_node.id - 2, |
273 | "index": 1, |
274 | "memory": 512, |
275 | "cores": [0, 1], |
276 | "hugepages_set": [{"page_size": 1024, "total": 1024}], |
277 | }, |
278 | { |
279 | + "id": numa_node.id - 1, |
280 | "index": 2, |
281 | "memory": 1024, |
282 | "cores": [2, 3], |
283 | "hugepages_set": [{"page_size": 1024, "total": 2048}], |
284 | }, |
285 | { |
286 | + "id": numa_node.id, |
287 | "index": 3, |
288 | "memory": 2048, |
289 | "cores": [4, 5], |
290 | diff --git a/src/maasserver/websockets/handlers/tests/test_node_device.py b/src/maasserver/websockets/handlers/tests/test_node_device.py |
291 | new file mode 100644 |
292 | index 0000000..beea5dd |
293 | --- /dev/null |
294 | +++ b/src/maasserver/websockets/handlers/tests/test_node_device.py |
295 | @@ -0,0 +1,51 @@ |
296 | +# Copyright 2020 Canonical Ltd. This software is licensed under the |
297 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
298 | + |
299 | +"""Tests for `maasserver.websockets.handlers.node_device`""" |
300 | + |
301 | +from maasserver.testing.factory import factory |
302 | +from maasserver.testing.testcase import MAASServerTestCase |
303 | +from maasserver.websockets.base import dehydrate_datetime, HandlerPKError |
304 | +from maasserver.websockets.handlers.node_device import NodeDeviceHandler |
305 | + |
306 | + |
307 | +class TestNodeDeviceHandler(MAASServerTestCase): |
308 | + def dehydrate_node_device(self, node_device): |
309 | + return { |
310 | + "id": node_device.id, |
311 | + "created": dehydrate_datetime(node_device.created), |
312 | + "updated": dehydrate_datetime(node_device.updated), |
313 | + "bus": node_device.bus, |
314 | + "hardware_type": node_device.hardware_type, |
315 | + "vendor_id": node_device.vendor_id, |
316 | + "product_id": node_device.product_id, |
317 | + "vendor_name": node_device.vendor_name, |
318 | + "product_name": node_device.product_name, |
319 | + "commissioning_driver": node_device.commissioning_driver, |
320 | + "bus_number": node_device.bus_number, |
321 | + "device_number": node_device.device_number, |
322 | + "pci_address": node_device.pci_address, |
323 | + "physical_blockdevice_id": node_device.physical_blockdevice_id, |
324 | + "physical_interface_id": node_device.physical_interface_id, |
325 | + "numa_node_id": node_device.numa_node_id, |
326 | + "node_id": node_device.node_id, |
327 | + } |
328 | + |
329 | + def test_list(self): |
330 | + user = factory.make_User() |
331 | + handler = NodeDeviceHandler(user, {}, None) |
332 | + node = factory.make_Node_with_Interface_on_Subnet() |
333 | + factory.make_Node() |
334 | + |
335 | + self.assertEqual( |
336 | + [ |
337 | + self.dehydrate_node_device(node_device) |
338 | + for node_device in node.node_devices.all() |
339 | + ], |
340 | + handler.list({"system_id": node.system_id}), |
341 | + ) |
342 | + |
343 | + def test_list_raises_error_if_no_system_id(self): |
344 | + user = factory.make_User() |
345 | + handler = NodeDeviceHandler(user, {}, None) |
346 | + self.assertRaises(HandlerPKError, handler.list, {}) |
347 | diff --git a/src/maasserver/websockets/tests/test_protocol.py b/src/maasserver/websockets/tests/test_protocol.py |
348 | index 3007e43..b2cba6a 100644 |
349 | --- a/src/maasserver/websockets/tests/test_protocol.py |
350 | +++ b/src/maasserver/websockets/tests/test_protocol.py |
351 | @@ -775,6 +775,7 @@ ALL_NOTIFIERS = ( |
352 | "fabric", |
353 | "iprange", |
354 | "machine", |
355 | + "nodedevice", |
356 | "notification", |
357 | "notificationdismissal", |
358 | "packagerepository", |
359 | @@ -809,6 +810,7 @@ ALL_HANDLERS = ( |
360 | "general", |
361 | "iprange", |
362 | "machine", |
363 | + "nodedevice", |
364 | "noderesult", |
365 | "notification", |
366 | "packagerepository", |
UNIT TESTS websocket lp:~ltrager/maas/+git/maas into -b master lp:~maas-committers/maas
-b node_device_
STATUS: FAILED maas-ci. internal: 8080/job/ maas/job/ branch- tester/ 8908/console 3a7c82ec7b88e11 74c53d9003
LOG: http://
COMMIT: 4cc0b29b718e96d