Merge ~adam-collard/maas:clone-errors-system-id into maas:master

Proposed by Adam Collard
Status: Merged
Approved by: Adam Collard
Approved revision: 1268d9c285fe80637f59057bf6397f08c56fcef0
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~adam-collard/maas:clone-errors-system-id
Merge into: maas:master
Diff against target: 149 lines (+63/-5)
3 files modified
src/maasserver/node_action.py (+23/-3)
src/maasserver/tests/test_node_action.py (+35/-0)
src/maasserver/websockets/handlers/tests/test_machine.py (+5/-2)
Reviewer Review Type Date Requested Status
Alberto Donato (community) Approve
MAAS Lander Approve
Review via email: mp+407954@code.launchpad.net

Commit message

Add system_id to clone errors

Annotate JSON from Django form errors with system_id where we have it.

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

UNIT TESTS
-b clone-errors-system-id lp:~adam-collard/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: edf98d2291446c57933473c6183748c71c2b98e2

review: Approve
Revision history for this message
Alberto Donato (ack) wrote :

nice! +1

small nit inline

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/maasserver/node_action.py b/src/maasserver/node_action.py
2index 2162065..af16a5f 100644
3--- a/src/maasserver/node_action.py
4+++ b/src/maasserver/node_action.py
5@@ -15,6 +15,7 @@ order as they do in `ACTION_CLASSES`.
6
7 from abc import ABCMeta, abstractmethod, abstractproperty
8 from collections import OrderedDict
9+import json
10
11 from crochet import TimeoutError
12 from django.core.exceptions import ValidationError
13@@ -969,6 +970,25 @@ class Clone(NodeAction):
14 def get_node_action_audit_description(self, action):
15 return self.audit_description % action.node.hostname
16
17+ def _format_field_errors_as_json(self, field_errors):
18+ rich_json_data = []
19+ base_data = field_errors.as_data()
20+ field_json = field_errors.get_json_data()
21+ for error, error_json in zip(base_data, field_json):
22+ # Annotate base JSON data with specifics
23+ if error.params and "system_id" in error.params:
24+ error_json["system_id"] = error.params["system_id"]
25+ rich_json_data.append(error_json)
26+ return rich_json_data
27+
28+ def _format_errors_as_json(self, error_dict):
29+ return json.dumps(
30+ {
31+ field: self._format_field_errors_as_json(error)
32+ for field, error in error_dict.items()
33+ }
34+ )
35+
36 def _execute(
37 self,
38 destinations=None,
39@@ -996,18 +1016,18 @@ class Clone(NodeAction):
40 _error_data=form.errors,
41 )
42 if not form.is_valid():
43- raise NodeActionError(form.errors.as_json())
44+ raise NodeActionError(self._format_errors_as_json(form.errors))
45 try:
46 form.save()
47 except ValidationError as exc:
48- raise NodeActionError(exc.errors.as_json())
49+ raise NodeActionError(self._format_errors_as_json(exc.errors))
50 if _error_data:
51 for name, error_list in _error_data.items():
52 if name in form.errors:
53 form.errors[name].extend(error_list)
54 else:
55 form.errors[name] = error_list
56- raise NodeActionError(form.errors.as_json())
57+ raise NodeActionError(self._format_errors_as_json(form.errors))
58
59
60 ACTION_CLASSES = (
61diff --git a/src/maasserver/tests/test_node_action.py b/src/maasserver/tests/test_node_action.py
62index a47d046..897d5f9 100644
63--- a/src/maasserver/tests/test_node_action.py
64+++ b/src/maasserver/tests/test_node_action.py
65@@ -1860,6 +1860,41 @@ class TestCloneAction(MAASServerTestCase):
66 audit_event.description, f"Cloning from '{source.hostname}'."
67 )
68
69+ def test_clone_errors_include_system_id(self):
70+ user = factory.make_admin()
71+ request = factory.make_fake_request("/")
72+ request.user = user
73+ source = factory.make_Machine(
74+ status=NODE_STATUS.READY, with_boot_disk=False
75+ )
76+ factory.make_PhysicalBlockDevice(
77+ node=source, size=8 * 1024 ** 3, name="sda"
78+ )
79+ destination = factory.make_Machine(
80+ status=NODE_STATUS.READY, with_boot_disk=False
81+ )
82+ factory.make_PhysicalBlockDevice(
83+ node=destination, size=4 * 1024 ** 3, name="sda"
84+ )
85+ action = Clone(source, user, request)
86+ exception = self.assertRaises(
87+ NodeActionError,
88+ action.execute,
89+ destinations=[destination.system_id],
90+ storage=True,
91+ )
92+ (error,) = exception.args
93+ self.assertEqual(
94+ json.loads(error)["destinations"],
95+ [
96+ {
97+ "code": "storage",
98+ "message": f"{destination} is invalid: destination boot disk(sda) is smaller than source boot disk(sda)",
99+ "system_id": destination.system_id,
100+ }
101+ ],
102+ )
103+
104
105 class TestActionsErrorHandling(MAASServerTestCase):
106 """Tests for error handling in actions.
107diff --git a/src/maasserver/websockets/handlers/tests/test_machine.py b/src/maasserver/websockets/handlers/tests/test_machine.py
108index c871158..fb32526 100644
109--- a/src/maasserver/websockets/handlers/tests/test_machine.py
110+++ b/src/maasserver/websockets/handlers/tests/test_machine.py
111@@ -3705,7 +3705,7 @@ class TestMachineHandler(MAASServerTestCase):
112 node.distro_series, Equals(osystem["releases"][0]["name"])
113 )
114
115- def test_action_clone_errors_bundled(self):
116+ def test_clone_errors_bundled(self):
117 user = factory.make_admin()
118 node = factory.make_Node()
119
120@@ -3742,7 +3742,7 @@ class TestMachineHandler(MAASServerTestCase):
121 },
122 )
123
124- def test_action_clone_errors_storage(self):
125+ def test_clone_errors_storage(self):
126 user = factory.make_admin()
127 request = HttpRequest()
128 request.user = user
129@@ -3789,10 +3789,12 @@ class TestMachineHandler(MAASServerTestCase):
130 {
131 "message": f"{destination1} is invalid: destination boot disk(sda) is smaller than source boot disk(sda)",
132 "code": "storage",
133+ "system_id": destination1.system_id,
134 },
135 {
136 "message": f"{destination2} is invalid: destination boot disk(sda) is smaller than source boot disk(sda)",
137 "code": "storage",
138+ "system_id": destination2.system_id,
139 },
140 ],
141 },
142@@ -3860,6 +3862,7 @@ class TestMachineHandler(MAASServerTestCase):
143 {
144 "message": f"{destination1} is invalid: destination boot disk(sda) is smaller than source boot disk(sda)",
145 "code": "storage",
146+ "system_id": destination1.system_id,
147 },
148 ],
149 },

Subscribers

People subscribed via source and target branches