Merge lp:~rvb/maas/backport-fixes into lp:maas/1.2

Proposed by Raphaël Badin
Status: Merged
Approved by: Raphaël Badin
Approved revision: no longer in the source branch.
Merged at revision: 1375
Proposed branch: lp:~rvb/maas/backport-fixes
Merge into: lp:maas/1.2
Diff against target: 307 lines (+116/-29)
6 files modified
src/maasserver/api.py (+29/-3)
src/maasserver/models/node.py (+2/-0)
src/maasserver/testing/factory.py (+19/-0)
src/maasserver/tests/test_api.py (+46/-0)
src/maasserver/tests/test_forms.py (+7/-26)
src/maasserver/tests/test_node.py (+13/-0)
To merge this branch: bzr merge lp:~rvb/maas/backport-fixes
Reviewer Review Type Date Requested Status
Raphaël Badin (community) Approve
Review via email: mp+160809@code.launchpad.net

Commit message

Backport revisions 1468 and 1469.

To post a comment you must log in.
Revision history for this message
Raphaël Badin (rvb) wrote :

Simple backport, self-approving.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/api.py'
2--- src/maasserver/api.py 2013-03-12 16:28:26 +0000
3+++ src/maasserver/api.py 2013-04-25 07:58:26 +0000
4@@ -65,6 +65,7 @@
5 "FilesHandler",
6 "get_oauth_token",
7 "MaasHandler",
8+ "NodeGroupHandler",
9 "NodeGroupsHandler",
10 "NodeGroupInterfaceHandler",
11 "NodeGroupInterfacesHandler",
12@@ -149,6 +150,7 @@
13 from maasserver.forms import (
14 get_node_create_form,
15 get_node_edit_form,
16+ NodeGroupEdit,
17 NodeGroupInterfaceForm,
18 NodeGroupWithInterfacesForm,
19 TagForm,
20@@ -457,6 +459,9 @@
21 )
22
23
24+METHOD_RESERVED_ADMIN = "That method is reserved for admin users."
25+
26+
27 def store_node_power_parameters(node, request):
28 """Store power parameters in request.
29
30@@ -1363,7 +1368,7 @@
31 nodegroup.accept()
32 return HttpResponse("Nodegroup(s) accepted.", status=httplib.OK)
33 else:
34- raise PermissionDenied("That method is reserved to admin users.")
35+ raise PermissionDenied(METHOD_RESERVED_ADMIN)
36
37 @operation(idempotent=False)
38 def reject(self, request):
39@@ -1381,7 +1386,7 @@
40 nodegroup.reject()
41 return HttpResponse("Nodegroup(s) rejected.", status=httplib.OK)
42 else:
43- raise PermissionDenied("That method is reserved to admin users.")
44+ raise PermissionDenied(METHOD_RESERVED_ADMIN)
45
46 @classmethod
47 def resource_uri(cls):
48@@ -1418,7 +1423,7 @@
49 Each NodeGroup has its own uuid.
50 """
51
52- create = update = delete = None
53+ create = delete = None
54 fields = DISPLAYED_NODEGROUP_FIELDS
55
56 def read(self, request, uuid):
57@@ -1433,6 +1438,27 @@
58 uuid = nodegroup.uuid
59 return ('nodegroup_handler', [uuid])
60
61+ def update(self, request, uuid):
62+ """Update a specific cluster.
63+
64+ :param name: The new DNS name for this cluster.
65+ :type name: basestring
66+ :param cluster_name: The new name for this cluster.
67+ :type cluster_name: basestring
68+ :param status: The new status for this cluster (see
69+ vocabulary `NODEGROUP_STATUS`).
70+ :type status: int
71+ """
72+ if not request.user.is_superuser:
73+ raise PermissionDenied(METHOD_RESERVED_ADMIN)
74+ nodegroup = get_object_or_404(NodeGroup, uuid=uuid)
75+ data = get_overrided_query_dict(model_to_dict(nodegroup), request.data)
76+ form = NodeGroupEdit(instance=nodegroup, data=data)
77+ if form.is_valid():
78+ return form.save()
79+ else:
80+ raise ValidationError(form.errors)
81+
82 @operation(idempotent=False)
83 def update_leases(self, request, uuid):
84 """Submit latest state of DHCP leases within the cluster.
85
86=== modified file 'src/maasserver/models/node.py'
87--- src/maasserver/models/node.py 2013-01-14 16:16:57 +0000
88+++ src/maasserver/models/node.py 2013-04-25 07:58:26 +0000
89@@ -395,6 +395,8 @@
90 node.cpu_count = cpu_count or 0
91 node.memory = memory
92 for tag in tag_manager.all():
93+ if not tag.definition:
94+ continue
95 has_tag = evaluator(tag.definition)
96 if has_tag:
97 node.tags.add(tag)
98
99=== modified file 'src/maasserver/testing/factory.py'
100--- src/maasserver/testing/factory.py 2013-03-07 16:26:00 +0000
101+++ src/maasserver/testing/factory.py 2013-04-25 07:58:26 +0000
102@@ -210,6 +210,25 @@
103 ng.save()
104 return ng
105
106+ def make_unrenamable_nodegroup_with_node(self):
107+ """Create a `NodeGroup` that can't be renamed, and `Node`.
108+
109+ Node groups can't be renamed while they are in an accepted state, have
110+ DHCP and DNS management enabled, and have a node that is in allocated
111+ state.
112+
113+ :return: tuple: (`NodeGroup`, `Node`).
114+ """
115+ name = self.make_name('original-name')
116+ nodegroup = self.make_node_group(
117+ name=name, status=NODEGROUP_STATUS.ACCEPTED)
118+ interface = nodegroup.get_managed_interface()
119+ interface.management = NODEGROUPINTERFACE_MANAGEMENT.DHCP_AND_DNS
120+ interface.save()
121+ node = self.make_node(
122+ nodegroup=nodegroup, status=NODE_STATUS.ALLOCATED)
123+ return nodegroup, node
124+
125 def make_node_group_interface(self, nodegroup, ip=None,
126 router_ip=None, network=None,
127 subnet_mask=None, broadcast_ip=None,
128
129=== modified file 'src/maasserver/tests/test_api.py'
130--- src/maasserver/tests/test_api.py 2013-03-12 16:28:26 +0000
131+++ src/maasserver/tests/test_api.py 2013-04-25 07:58:26 +0000
132@@ -77,6 +77,7 @@
133 NODE_STATUS,
134 NODE_STATUS_CHOICES_DICT,
135 NODEGROUP_STATUS,
136+ NODEGROUP_STATUS_CHOICES,
137 NODEGROUPINTERFACE_MANAGEMENT,
138 )
139 from maasserver.exceptions import (
140@@ -4394,6 +4395,51 @@
141 self.get_uri('nodegroups/%s/' % factory.make_name('nodegroup')))
142 self.assertEqual(httplib.NOT_FOUND, response.status_code)
143
144+ def test_PUT_reserved_to_admin_users(self):
145+ nodegroup = factory.make_node_group()
146+ response = self.client.put(
147+ reverse('nodegroup_handler', args=[nodegroup.uuid]),
148+ {'name': factory.make_name("new-name")})
149+
150+ self.assertEqual(httplib.FORBIDDEN, response.status_code)
151+
152+ def test_PUT_updates_nodegroup(self):
153+ # The api allows the updating of a NodeGroup.
154+ nodegroup = factory.make_node_group()
155+ self.become_admin()
156+ new_name = factory.make_name("new-name")
157+ new_cluster_name = factory.make_name("new-cluster-name")
158+ new_status = factory.getRandomChoice(
159+ NODEGROUP_STATUS_CHOICES, but_not=[nodegroup.status])
160+ response = self.client.put(
161+ reverse('nodegroup_handler', args=[nodegroup.uuid]),
162+ {
163+ 'name': new_name,
164+ 'cluster_name': new_cluster_name,
165+ 'status': new_status,
166+ })
167+
168+ self.assertEqual(httplib.OK, response.status_code, response.content)
169+ nodegroup = reload_object(nodegroup)
170+ self.assertEqual(
171+ (new_name, new_cluster_name, new_status),
172+ (nodegroup.name, nodegroup.cluster_name, nodegroup.status))
173+
174+ def test_PUT_updates_nodegroup_validates_data(self):
175+ nodegroup, _ = factory.make_unrenamable_nodegroup_with_node()
176+ self.become_admin()
177+ new_name = factory.make_name("new-name")
178+ response = self.client.put(
179+ reverse('nodegroup_handler', args=[nodegroup.uuid]),
180+ {'name': new_name})
181+
182+ parsed_result = json.loads(response.content)
183+
184+ self.assertEqual(httplib.BAD_REQUEST, response.status_code)
185+ self.assertIn(
186+ "Can't rename DNS zone",
187+ parsed_result['name'][0])
188+
189 def test_update_leases_processes_empty_leases_dict(self):
190 nodegroup = factory.make_node_group()
191 factory.make_dhcp_lease(nodegroup=nodegroup)
192
193=== modified file 'src/maasserver/tests/test_forms.py'
194--- src/maasserver/tests/test_forms.py 2012-12-04 02:31:07 +0000
195+++ src/maasserver/tests/test_forms.py 2013-04-25 07:58:26 +0000
196@@ -878,25 +878,6 @@
197 ])
198
199
200-def make_unrenamable_nodegroup_with_node():
201- """Create a `NodeGroup` that can't be renamed, and `Node`.
202-
203- Node groups can't be renamed while they are in an accepted state, have
204- DHCP and DNS management enabled, and have a node that is in allocated
205- state.
206-
207- :return: tuple: (`NodeGroup`, `Node`).
208- """
209- name = factory.make_name('original-name')
210- nodegroup = factory.make_node_group(
211- name=name, status=NODEGROUP_STATUS.ACCEPTED)
212- interface = nodegroup.get_managed_interface()
213- interface.management = NODEGROUPINTERFACE_MANAGEMENT.DHCP_AND_DNS
214- interface.save()
215- node = factory.make_node(nodegroup=nodegroup, status=NODE_STATUS.ALLOCATED)
216- return nodegroup, node
217-
218-
219 class TestNodeGroupEdit(TestCase):
220
221 def make_form_data(self, nodegroup):
222@@ -918,14 +899,14 @@
223 self.assertEqual(new_name, reload_object(nodegroup).name)
224
225 def test_refuses_name_change_if_dns_managed_and_nodes_in_use(self):
226- nodegroup, node = make_unrenamable_nodegroup_with_node()
227+ nodegroup, node = factory.make_unrenamable_nodegroup_with_node()
228 data = self.make_form_data(nodegroup)
229 data['name'] = factory.make_name('new-name')
230 form = NodeGroupEdit(instance=nodegroup, data=data)
231 self.assertFalse(form.is_valid())
232
233 def test_accepts_unchanged_name(self):
234- nodegroup, node = make_unrenamable_nodegroup_with_node()
235+ nodegroup, node = factory.make_unrenamable_nodegroup_with_node()
236 original_name = nodegroup.name
237 form = NodeGroupEdit(
238 instance=nodegroup, data=self.make_form_data(nodegroup))
239@@ -934,7 +915,7 @@
240 self.assertEqual(original_name, reload_object(nodegroup).name)
241
242 def test_accepts_omitted_name(self):
243- nodegroup, node = make_unrenamable_nodegroup_with_node()
244+ nodegroup, node = factory.make_unrenamable_nodegroup_with_node()
245 original_name = nodegroup.name
246 data = self.make_form_data(nodegroup)
247 del data['name']
248@@ -944,7 +925,7 @@
249 self.assertEqual(original_name, reload_object(nodegroup).name)
250
251 def test_accepts_name_change_if_nodegroup_not_accepted(self):
252- nodegroup, node = make_unrenamable_nodegroup_with_node()
253+ nodegroup, node = factory.make_unrenamable_nodegroup_with_node()
254 nodegroup.status = NODEGROUP_STATUS.PENDING
255 data = self.make_form_data(nodegroup)
256 data['name'] = factory.make_name('new-name')
257@@ -952,7 +933,7 @@
258 self.assertTrue(form.is_valid())
259
260 def test_accepts_name_change_if_dns_managed_but_no_nodes_in_use(self):
261- nodegroup, node = make_unrenamable_nodegroup_with_node()
262+ nodegroup, node = factory.make_unrenamable_nodegroup_with_node()
263 node.status = NODE_STATUS.READY
264 node.save()
265 data = self.make_form_data(nodegroup)
266@@ -963,7 +944,7 @@
267 self.assertEqual(data['name'], reload_object(nodegroup).name)
268
269 def test_accepts_name_change_if_nodes_in_use_but_dns_not_managed(self):
270- nodegroup, node = make_unrenamable_nodegroup_with_node()
271+ nodegroup, node = factory.make_unrenamable_nodegroup_with_node()
272 interface = nodegroup.get_managed_interface()
273 interface.management = NODEGROUPINTERFACE_MANAGEMENT.DHCP
274 interface.save()
275@@ -975,7 +956,7 @@
276 self.assertEqual(data['name'], reload_object(nodegroup).name)
277
278 def test_accepts_name_change_if_nodegroup_has_no_interface(self):
279- nodegroup, node = make_unrenamable_nodegroup_with_node()
280+ nodegroup, node = factory.make_unrenamable_nodegroup_with_node()
281 NodeGroupInterface.objects.filter(nodegroup=nodegroup).delete()
282 data = self.make_form_data(nodegroup)
283 data['name'] = factory.make_name('new-name')
284
285=== modified file 'src/maasserver/tests/test_node.py'
286--- src/maasserver/tests/test_node.py 2012-11-16 13:50:43 +0000
287+++ src/maasserver/tests/test_node.py 2013-04-25 07:58:26 +0000
288@@ -586,6 +586,19 @@
289 node = reload_object(node)
290 self.assertEqual([], list(node.tags.all()))
291
292+ def test_hardware_updates_ignores_empty_tags(self):
293+ # Tags with empty definitions are ignored when
294+ # node.set_hardware_details gets called.
295+ factory.make_tag(definition='')
296+ node = factory.make_node()
297+ node.save()
298+ xmlbytes = '<node/>'
299+ node.set_hardware_details(xmlbytes)
300+ node = reload_object(node)
301+ # The real test is that node.set_hardware_details does not blow
302+ # up, see bug 1131418.
303+ self.assertEqual([], list(node.tags.all()))
304+
305 def test_fqdn_returns_hostname_if_dns_not_managed(self):
306 nodegroup = factory.make_node_group(
307 name=factory.getRandomString(),

Subscribers

People subscribed via source and target branches

to status/vote changes: