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
diff --git a/src/maasserver/websockets/handlers/controller.py b/src/maasserver/websockets/handlers/controller.py
index d5ab7c2..7365b5b 100644
--- a/src/maasserver/websockets/handlers/controller.py
+++ b/src/maasserver/websockets/handlers/controller.py
@@ -93,6 +93,7 @@ class ControllerHandler(NodeHandler):
93 "set_script_result_suppressed",93 "set_script_result_suppressed",
94 "set_script_result_unsuppressed",94 "set_script_result_unsuppressed",
95 "get_latest_failed_testing_script_results",95 "get_latest_failed_testing_script_results",
96 "update_interface",
96 ]97 ]
97 form = ControllerForm98 form = ControllerForm
98 exclude = [99 exclude = [
@@ -171,7 +172,11 @@ class ControllerHandler(NodeHandler):
171 data = super().dehydrate(obj, data, for_list=for_list)172 data = super().dehydrate(obj, data, for_list=for_list)
172173
173 vlan_counts = Counter()174 vlan_counts = Counter()
174 for vlan_id in obj.vlan_ids:175 vlan_ids = [
176 interface.vlan_id
177 for interface in obj.current_config.interface_set.all()
178 ]
179 for vlan_id in vlan_ids:
175 vlan_counts[self._vlans_ha[vlan_id]] += 1180 vlan_counts[self._vlans_ha[vlan_id]] += 1
176181
177 data.update(182 data.update(
@@ -187,10 +192,8 @@ class ControllerHandler(NodeHandler):
187 }192 }
188 )193 )
189 if not for_list:194 if not for_list:
190 data["vlan_ids"] = [195 data["vlan_ids"] = vlan_ids
191 interface.vlan_id196
192 for interface in obj.current_config.interface_set.all()
193 ]
194 return data197 return data
195198
196 def dehydrate_versions(self, info):199 def dehydrate_versions(self, info):
diff --git a/src/maasserver/websockets/handlers/machine.py b/src/maasserver/websockets/handlers/machine.py
index 8c27240..e1ad271 100644
--- a/src/maasserver/websockets/handlers/machine.py
+++ b/src/maasserver/websockets/handlers/machine.py
@@ -45,8 +45,6 @@ from maasserver.forms.interface import (
45 AcquiredBridgeInterfaceForm,45 AcquiredBridgeInterfaceForm,
46 BondInterfaceForm,46 BondInterfaceForm,
47 BridgeInterfaceForm,47 BridgeInterfaceForm,
48 DeployedInterfaceForm,
49 InterfaceForm,
50 PhysicalInterfaceForm,48 PhysicalInterfaceForm,
51 VLANInterfaceForm,49 VLANInterfaceForm,
52)50)
@@ -637,11 +635,6 @@ class MachineHandler(NodeHandler):
637 else:635 else:
638 form.save()636 form.save()
639637
640 def _update_obj_tags(self, obj, params):
641 if "tags" in params:
642 obj.tags = params["tags"]
643 obj.save(update_fields=["tags"])
644
645 def update_disk(self, params):638 def update_disk(self, params):
646 """Update disk information."""639 """Update disk information."""
647 node = self._get_node_or_permission_error(640 node = self._get_node_or_permission_error(
@@ -1041,28 +1034,6 @@ class MachineHandler(NodeHandler):
1041 else:1034 else:
1042 raise ValidationError(form.errors)1035 raise ValidationError(form.errors)
10431036
1044 def update_interface(self, params):
1045 """Update the interface."""
1046 node = self._get_node_or_permission_error(
1047 params, permission=self._meta.edit_permission
1048 )
1049 interface = Interface.objects.get(
1050 node_config__node=node, id=params["interface_id"]
1051 )
1052 if node.status == NODE_STATUS.DEPLOYED:
1053 interface_form = DeployedInterfaceForm
1054 else:
1055 interface_form = InterfaceForm.get_interface_form(interface.type)
1056 form = interface_form(instance=interface, data=params)
1057 if form.is_valid():
1058 interface = form.save()
1059 self._update_obj_tags(interface, params)
1060 else:
1061 raise ValidationError(form.errors)
1062 if "mode" in params:
1063 self.link_subnet(params)
1064 return self.full_dehydrate(node)
1065
1066 def delete_interface(self, params):1037 def delete_interface(self, params):
1067 """Delete the interface."""1038 """Delete the interface."""
1068 node = self._get_node_or_permission_error(1039 node = self._get_node_or_permission_error(
@@ -1073,45 +1044,6 @@ class MachineHandler(NodeHandler):
1073 )1044 )
1074 interface.delete()1045 interface.delete()
10751046
1076 def link_subnet(self, params):
1077 """Create or update the link."""
1078 node = self._get_node_or_permission_error(
1079 params, permission=self._meta.edit_permission
1080 )
1081 interface = Interface.objects.get(
1082 node_config__node=node, id=params["interface_id"]
1083 )
1084 subnet = None
1085 if "subnet" in params:
1086 subnet = Subnet.objects.get(id=params["subnet"])
1087 if "link_id" in params:
1088 if interface.ip_addresses.filter(id=params["link_id"]).exists():
1089 # We are updating an already existing link. Which may have
1090 # been deleted.
1091 interface.update_link_by_id(
1092 params["link_id"],
1093 params["mode"],
1094 subnet,
1095 ip_address=params.get("ip_address", None),
1096 )
1097 else:
1098 # We are creating a new link.
1099 interface.link_subnet(
1100 params["mode"],
1101 subnet,
1102 ip_address=params.get("ip_address", None),
1103 )
1104
1105 def unlink_subnet(self, params):
1106 """Delete the link."""
1107 node = self._get_node_or_permission_error(
1108 params, permission=self._meta.edit_permission
1109 )
1110 interface = Interface.objects.get(
1111 node_config__node=node, id=params["interface_id"]
1112 )
1113 interface.unlink_subnet_by_id(params["link_id"])
1114
1115 @asynchronous(timeout=45)1047 @asynchronous(timeout=45)
1116 def check_power(self, params):1048 def check_power(self, params):
1117 """Check the power state of the node."""1049 """Check the power state of the node."""
@@ -1140,12 +1072,6 @@ class MachineHandler(NodeHandler):
1140 d.addCallback(partial(deferToDatabase, update_state))1072 d.addCallback(partial(deferToDatabase, update_state))
1141 return d1073 return d
11421074
1143 def _get_node_or_permission_error(self, params, permission=None):
1144 node = self.get_object(params, permission=permission)
1145 if node.locked:
1146 raise HandlerPermissionError()
1147 return node
1148
1149 def get_workload_annotations(self, params):1075 def get_workload_annotations(self, params):
1150 """Get the owner data for a machine, known as workload annotations."""1076 """Get the owner data for a machine, known as workload annotations."""
1151 machine = self._get_node_or_permission_error(1077 machine = self._get_node_or_permission_error(
diff --git a/src/maasserver/websockets/handlers/node.py b/src/maasserver/websockets/handlers/node.py
index 7c34b5a..ae118db 100644
--- a/src/maasserver/websockets/handlers/node.py
+++ b/src/maasserver/websockets/handlers/node.py
@@ -9,6 +9,7 @@ from itertools import chain
9import logging9import logging
10from operator import attrgetter, itemgetter10from operator import attrgetter, itemgetter
1111
12from django.core.exceptions import ValidationError
12from django.db.models import Prefetch13from django.db.models import Prefetch
13from lxml import etree14from lxml import etree
1415
@@ -21,6 +22,11 @@ from maasserver.enum import (
21 NODE_TYPE,22 NODE_TYPE,
22 POWER_STATE,23 POWER_STATE,
23)24)
25from maasserver.forms.interface import (
26 ControllerInterfaceForm,
27 DeployedInterfaceForm,
28 InterfaceForm,
29)
24from maasserver.models import (30from maasserver.models import (
25 CacheSet,31 CacheSet,
26 Config,32 Config,
@@ -28,6 +34,7 @@ from maasserver.models import (
28 Interface,34 Interface,
29 NUMANode,35 NUMANode,
30 PhysicalBlockDevice,36 PhysicalBlockDevice,
37 Subnet,
31 Tag,38 Tag,
32 VirtualBlockDevice,39 VirtualBlockDevice,
33 VolumeGroup,40 VolumeGroup,
@@ -1180,3 +1187,78 @@ class NodeHandler(TimestampedModelHandler):
1180 f"Cannot add tag {tag.name} to node because it has a definition"1187 f"Cannot add tag {tag.name} to node because it has a definition"
1181 )1188 )
1182 node.tags.set(tags)1189 node.tags.set(tags)
1190
1191 def update_interface(self, params):
1192 """Update the interface."""
1193 node = self._get_node_or_permission_error(
1194 params, permission=self._meta.edit_permission
1195 )
1196 interface = Interface.objects.get(
1197 node_config__node=node, id=params["interface_id"]
1198 )
1199 if node.is_controller:
1200 interface_form = ControllerInterfaceForm
1201 elif node.status == NODE_STATUS.DEPLOYED:
1202 interface_form = DeployedInterfaceForm
1203 else:
1204 interface_form = InterfaceForm.get_interface_form(interface.type)
1205 form = interface_form(instance=interface, data=params)
1206 if form.is_valid():
1207 interface = form.save()
1208 self._update_obj_tags(interface, params)
1209 else:
1210 raise ValidationError(form.errors)
1211 if "mode" in params:
1212 self.link_subnet(params)
1213 node.refresh_from_db()
1214 return self.full_dehydrate(node)
1215
1216 def _get_node_or_permission_error(self, params, permission=None):
1217 node = self.get_object(params, permission=permission)
1218 if node.locked:
1219 raise HandlerPermissionError()
1220 return node
1221
1222 def _update_obj_tags(self, obj, params):
1223 if "tags" in params:
1224 obj.tags = params["tags"]
1225 obj.save(update_fields=["tags"])
1226
1227 def link_subnet(self, params):
1228 """Create or update the link."""
1229 node = self._get_node_or_permission_error(
1230 params, permission=self._meta.edit_permission
1231 )
1232 interface = Interface.objects.get(
1233 node_config__node=node, id=params["interface_id"]
1234 )
1235 subnet = None
1236 if "subnet" in params:
1237 subnet = Subnet.objects.get(id=params["subnet"])
1238 if "link_id" in params:
1239 if interface.ip_addresses.filter(id=params["link_id"]).exists():
1240 # We are updating an already existing link. Which may have
1241 # been deleted.
1242 interface.update_link_by_id(
1243 params["link_id"],
1244 params["mode"],
1245 subnet,
1246 ip_address=params.get("ip_address", None),
1247 )
1248 else:
1249 # We are creating a new link.
1250 interface.link_subnet(
1251 params["mode"],
1252 subnet,
1253 ip_address=params.get("ip_address", None),
1254 )
1255
1256 def unlink_subnet(self, params):
1257 """Delete the link."""
1258 node = self._get_node_or_permission_error(
1259 params, permission=self._meta.edit_permission
1260 )
1261 interface = Interface.objects.get(
1262 node_config__node=node, id=params["interface_id"]
1263 )
1264 interface.unlink_subnet_by_id(params["link_id"])
diff --git a/src/maasserver/websockets/handlers/tests/test_controller.py b/src/maasserver/websockets/handlers/tests/test_controller.py
index f0aab9b..eda0b66 100644
--- a/src/maasserver/websockets/handlers/tests/test_controller.py
+++ b/src/maasserver/websockets/handlers/tests/test_controller.py
@@ -469,3 +469,30 @@ class TestControllerHandler(MAASServerTestCase):
469 controller.refresh_from_db()469 controller.refresh_from_db()
470 # deleting a region+rack controller changes it to just a region controller470 # deleting a region+rack controller changes it to just a region controller
471 self.assertEqual(controller.node_type, NODE_TYPE.REGION_CONTROLLER)471 self.assertEqual(controller.node_type, NODE_TYPE.REGION_CONTROLLER)
472
473 def test_update_interface(self):
474 admin = factory.make_admin()
475 vlan = factory.make_VLAN()
476 handler = ControllerHandler(admin, {}, None)
477 controller = factory.make_RegionRackController()
478 request = {
479 "name": controller.boot_interface.name,
480 "mac_address": controller.boot_interface.mac_address,
481 "tags": [],
482 "fabric": vlan.fabric.id,
483 "vlan": vlan.id,
484 "mode": "link_up",
485 "link_connected": True,
486 "link_speed": 0,
487 "interface_speed": 0,
488 "formatted_link_speed": 0,
489 "formatted_interface_speed": 0,
490 "type": controller.boot_interface.type,
491 "parents": controller.boot_interface.parents,
492 "primary": None,
493 "system_id": controller.system_id,
494 "interface_id": controller.boot_interface.id,
495 }
496 handler.update_interface(request)
497 controller.refresh_from_db()
498 self.assertEqual(controller.boot_interface.vlan, vlan)

Subscribers

People subscribed via source and target branches