Merge ~cgrabowski/maas:backport_to_3.2_add_update_interface_To_controller_ws_handler into maas:3.2

Proposed by Christian Grabowski
Status: Merged
Approved by: Christian Grabowski
Approved revision: 02234c475bedeb541c8c33f34a44a789cb31e97f
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~cgrabowski/maas:backport_to_3.2_add_update_interface_To_controller_ws_handler
Merge into: maas:3.2
Diff against target: 297 lines (+117/-79)
4 files modified
src/maasserver/websockets/handlers/controller.py (+8/-5)
src/maasserver/websockets/handlers/machine.py (+0/-74)
src/maasserver/websockets/handlers/node.py (+82/-0)
src/maasserver/websockets/handlers/tests/test_controller.py (+27/-0)
Reviewer Review Type Date Requested Status
Christian Grabowski Approve
MAAS Lander Approve
Review via email: mp+427622@code.launchpad.net

Commit message

ensure node is up to date before dehydrating
(cherry picked from commit 624798b11123c4696d80371ff66ab1b3487e76e8)

include controller interface form
(cherry picked from commit 819793ab4be1211efd768a09117f5f111aed833a)

use boot interface in test
(cherry picked from commit deef8f19afee791102c6a3f1349b30a19a87bfda)

move _update_obj_tags to the Node handler for both Controller and Machine handlers
(cherry picked from commit 459bb180a305056d41bc81a7c425bf30e31e582c)

move form import to correct file
(cherry picked from commit 608e094b658d1c5a96f707f436d712074bc91ab7)

move _get_node_or_permission_error to Node handler for use with Controller and Machine handlers
(cherry picked from commit b017a09d54633068ac0454cb99fab932d00a67b1)

move update_interface into Node handler for controller to inherit
(cherry picked from commit 948601b5b7a57bd9e8b8453e6de00976ba6394bf)

To post a comment you must log in.
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b backport_to_3.2_add_update_interface_To_controller_ws_handler lp:~cgrabowski/maas/+git/maas into -b 3.2 lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas-tester/227/consoleText
COMMIT: cdb8a1ae2046b3c01c388fae27a5edc250bd0f4f

review: Needs Fixing
02234c4... by Christian Grabowski

fix discrepancies between master and 3.2

Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b backport_to_3.2_add_update_interface_To_controller_ws_handler lp:~cgrabowski/maas/+git/maas into -b 3.2 lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas-tester/230/consoleText
COMMIT: 02234c475bedeb541c8c33f34a44a789cb31e97f

review: Needs Fixing
Revision history for this message
Christian Grabowski (cgrabowski) wrote :

jenkins: !test

Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b backport_to_3.2_add_update_interface_To_controller_ws_handler lp:~cgrabowski/maas/+git/maas into -b 3.2 lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: 02234c475bedeb541c8c33f34a44a789cb31e97f

review: Approve
Revision history for this message
Christian Grabowski (cgrabowski) wrote :

self-approve backport

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/maasserver/websockets/handlers/controller.py b/src/maasserver/websockets/handlers/controller.py
2index d5ab7c2..7365b5b 100644
3--- a/src/maasserver/websockets/handlers/controller.py
4+++ b/src/maasserver/websockets/handlers/controller.py
5@@ -93,6 +93,7 @@ class ControllerHandler(NodeHandler):
6 "set_script_result_suppressed",
7 "set_script_result_unsuppressed",
8 "get_latest_failed_testing_script_results",
9+ "update_interface",
10 ]
11 form = ControllerForm
12 exclude = [
13@@ -171,7 +172,11 @@ class ControllerHandler(NodeHandler):
14 data = super().dehydrate(obj, data, for_list=for_list)
15
16 vlan_counts = Counter()
17- for vlan_id in obj.vlan_ids:
18+ vlan_ids = [
19+ interface.vlan_id
20+ for interface in obj.current_config.interface_set.all()
21+ ]
22+ for vlan_id in vlan_ids:
23 vlan_counts[self._vlans_ha[vlan_id]] += 1
24
25 data.update(
26@@ -187,10 +192,8 @@ class ControllerHandler(NodeHandler):
27 }
28 )
29 if not for_list:
30- data["vlan_ids"] = [
31- interface.vlan_id
32- for interface in obj.current_config.interface_set.all()
33- ]
34+ data["vlan_ids"] = vlan_ids
35+
36 return data
37
38 def dehydrate_versions(self, info):
39diff --git a/src/maasserver/websockets/handlers/machine.py b/src/maasserver/websockets/handlers/machine.py
40index 8c27240..e1ad271 100644
41--- a/src/maasserver/websockets/handlers/machine.py
42+++ b/src/maasserver/websockets/handlers/machine.py
43@@ -45,8 +45,6 @@ from maasserver.forms.interface import (
44 AcquiredBridgeInterfaceForm,
45 BondInterfaceForm,
46 BridgeInterfaceForm,
47- DeployedInterfaceForm,
48- InterfaceForm,
49 PhysicalInterfaceForm,
50 VLANInterfaceForm,
51 )
52@@ -637,11 +635,6 @@ class MachineHandler(NodeHandler):
53 else:
54 form.save()
55
56- def _update_obj_tags(self, obj, params):
57- if "tags" in params:
58- obj.tags = params["tags"]
59- obj.save(update_fields=["tags"])
60-
61 def update_disk(self, params):
62 """Update disk information."""
63 node = self._get_node_or_permission_error(
64@@ -1041,28 +1034,6 @@ class MachineHandler(NodeHandler):
65 else:
66 raise ValidationError(form.errors)
67
68- def update_interface(self, params):
69- """Update the interface."""
70- node = self._get_node_or_permission_error(
71- params, permission=self._meta.edit_permission
72- )
73- interface = Interface.objects.get(
74- node_config__node=node, id=params["interface_id"]
75- )
76- if node.status == NODE_STATUS.DEPLOYED:
77- interface_form = DeployedInterfaceForm
78- else:
79- interface_form = InterfaceForm.get_interface_form(interface.type)
80- form = interface_form(instance=interface, data=params)
81- if form.is_valid():
82- interface = form.save()
83- self._update_obj_tags(interface, params)
84- else:
85- raise ValidationError(form.errors)
86- if "mode" in params:
87- self.link_subnet(params)
88- return self.full_dehydrate(node)
89-
90 def delete_interface(self, params):
91 """Delete the interface."""
92 node = self._get_node_or_permission_error(
93@@ -1073,45 +1044,6 @@ class MachineHandler(NodeHandler):
94 )
95 interface.delete()
96
97- def link_subnet(self, params):
98- """Create or update the link."""
99- node = self._get_node_or_permission_error(
100- params, permission=self._meta.edit_permission
101- )
102- interface = Interface.objects.get(
103- node_config__node=node, id=params["interface_id"]
104- )
105- subnet = None
106- if "subnet" in params:
107- subnet = Subnet.objects.get(id=params["subnet"])
108- if "link_id" in params:
109- if interface.ip_addresses.filter(id=params["link_id"]).exists():
110- # We are updating an already existing link. Which may have
111- # been deleted.
112- interface.update_link_by_id(
113- params["link_id"],
114- params["mode"],
115- subnet,
116- ip_address=params.get("ip_address", None),
117- )
118- else:
119- # We are creating a new link.
120- interface.link_subnet(
121- params["mode"],
122- subnet,
123- ip_address=params.get("ip_address", None),
124- )
125-
126- def unlink_subnet(self, params):
127- """Delete the link."""
128- node = self._get_node_or_permission_error(
129- params, permission=self._meta.edit_permission
130- )
131- interface = Interface.objects.get(
132- node_config__node=node, id=params["interface_id"]
133- )
134- interface.unlink_subnet_by_id(params["link_id"])
135-
136 @asynchronous(timeout=45)
137 def check_power(self, params):
138 """Check the power state of the node."""
139@@ -1140,12 +1072,6 @@ class MachineHandler(NodeHandler):
140 d.addCallback(partial(deferToDatabase, update_state))
141 return d
142
143- def _get_node_or_permission_error(self, params, permission=None):
144- node = self.get_object(params, permission=permission)
145- if node.locked:
146- raise HandlerPermissionError()
147- return node
148-
149 def get_workload_annotations(self, params):
150 """Get the owner data for a machine, known as workload annotations."""
151 machine = self._get_node_or_permission_error(
152diff --git a/src/maasserver/websockets/handlers/node.py b/src/maasserver/websockets/handlers/node.py
153index 7c34b5a..ae118db 100644
154--- a/src/maasserver/websockets/handlers/node.py
155+++ b/src/maasserver/websockets/handlers/node.py
156@@ -9,6 +9,7 @@ from itertools import chain
157 import logging
158 from operator import attrgetter, itemgetter
159
160+from django.core.exceptions import ValidationError
161 from django.db.models import Prefetch
162 from lxml import etree
163
164@@ -21,6 +22,11 @@ from maasserver.enum import (
165 NODE_TYPE,
166 POWER_STATE,
167 )
168+from maasserver.forms.interface import (
169+ ControllerInterfaceForm,
170+ DeployedInterfaceForm,
171+ InterfaceForm,
172+)
173 from maasserver.models import (
174 CacheSet,
175 Config,
176@@ -28,6 +34,7 @@ from maasserver.models import (
177 Interface,
178 NUMANode,
179 PhysicalBlockDevice,
180+ Subnet,
181 Tag,
182 VirtualBlockDevice,
183 VolumeGroup,
184@@ -1180,3 +1187,78 @@ class NodeHandler(TimestampedModelHandler):
185 f"Cannot add tag {tag.name} to node because it has a definition"
186 )
187 node.tags.set(tags)
188+
189+ def update_interface(self, params):
190+ """Update the interface."""
191+ node = self._get_node_or_permission_error(
192+ params, permission=self._meta.edit_permission
193+ )
194+ interface = Interface.objects.get(
195+ node_config__node=node, id=params["interface_id"]
196+ )
197+ if node.is_controller:
198+ interface_form = ControllerInterfaceForm
199+ elif node.status == NODE_STATUS.DEPLOYED:
200+ interface_form = DeployedInterfaceForm
201+ else:
202+ interface_form = InterfaceForm.get_interface_form(interface.type)
203+ form = interface_form(instance=interface, data=params)
204+ if form.is_valid():
205+ interface = form.save()
206+ self._update_obj_tags(interface, params)
207+ else:
208+ raise ValidationError(form.errors)
209+ if "mode" in params:
210+ self.link_subnet(params)
211+ node.refresh_from_db()
212+ return self.full_dehydrate(node)
213+
214+ def _get_node_or_permission_error(self, params, permission=None):
215+ node = self.get_object(params, permission=permission)
216+ if node.locked:
217+ raise HandlerPermissionError()
218+ return node
219+
220+ def _update_obj_tags(self, obj, params):
221+ if "tags" in params:
222+ obj.tags = params["tags"]
223+ obj.save(update_fields=["tags"])
224+
225+ def link_subnet(self, params):
226+ """Create or update the link."""
227+ node = self._get_node_or_permission_error(
228+ params, permission=self._meta.edit_permission
229+ )
230+ interface = Interface.objects.get(
231+ node_config__node=node, id=params["interface_id"]
232+ )
233+ subnet = None
234+ if "subnet" in params:
235+ subnet = Subnet.objects.get(id=params["subnet"])
236+ if "link_id" in params:
237+ if interface.ip_addresses.filter(id=params["link_id"]).exists():
238+ # We are updating an already existing link. Which may have
239+ # been deleted.
240+ interface.update_link_by_id(
241+ params["link_id"],
242+ params["mode"],
243+ subnet,
244+ ip_address=params.get("ip_address", None),
245+ )
246+ else:
247+ # We are creating a new link.
248+ interface.link_subnet(
249+ params["mode"],
250+ subnet,
251+ ip_address=params.get("ip_address", None),
252+ )
253+
254+ def unlink_subnet(self, params):
255+ """Delete the link."""
256+ node = self._get_node_or_permission_error(
257+ params, permission=self._meta.edit_permission
258+ )
259+ interface = Interface.objects.get(
260+ node_config__node=node, id=params["interface_id"]
261+ )
262+ interface.unlink_subnet_by_id(params["link_id"])
263diff --git a/src/maasserver/websockets/handlers/tests/test_controller.py b/src/maasserver/websockets/handlers/tests/test_controller.py
264index f0aab9b..eda0b66 100644
265--- a/src/maasserver/websockets/handlers/tests/test_controller.py
266+++ b/src/maasserver/websockets/handlers/tests/test_controller.py
267@@ -469,3 +469,30 @@ class TestControllerHandler(MAASServerTestCase):
268 controller.refresh_from_db()
269 # deleting a region+rack controller changes it to just a region controller
270 self.assertEqual(controller.node_type, NODE_TYPE.REGION_CONTROLLER)
271+
272+ def test_update_interface(self):
273+ admin = factory.make_admin()
274+ vlan = factory.make_VLAN()
275+ handler = ControllerHandler(admin, {}, None)
276+ controller = factory.make_RegionRackController()
277+ request = {
278+ "name": controller.boot_interface.name,
279+ "mac_address": controller.boot_interface.mac_address,
280+ "tags": [],
281+ "fabric": vlan.fabric.id,
282+ "vlan": vlan.id,
283+ "mode": "link_up",
284+ "link_connected": True,
285+ "link_speed": 0,
286+ "interface_speed": 0,
287+ "formatted_link_speed": 0,
288+ "formatted_interface_speed": 0,
289+ "type": controller.boot_interface.type,
290+ "parents": controller.boot_interface.parents,
291+ "primary": None,
292+ "system_id": controller.system_id,
293+ "interface_id": controller.boot_interface.id,
294+ }
295+ handler.update_interface(request)
296+ controller.refresh_from_db()
297+ self.assertEqual(controller.boot_interface.vlan, vlan)

Subscribers

People subscribed via source and target branches