Merge lp:~rvb/maas/bug-1234853 into lp:~maas-committers/maas/trunk

Proposed by Raphaël Badin
Status: Merged
Approved by: Raphaël Badin
Approved revision: no longer in the source branch.
Merged at revision: 1661
Proposed branch: lp:~rvb/maas/bug-1234853
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 129 lines (+31/-24)
5 files modified
src/maasserver/api.py (+3/-3)
src/maasserver/forms.py (+3/-10)
src/maasserver/tests/test_forms.py (+3/-10)
src/maasserver/tests/test_views_settings_clusters.py (+15/-0)
src/maasserver/views/settings_clusters.py (+7/-1)
To merge this branch: bzr merge lp:~rvb/maas/bug-1234853
Reviewer Review Type Date Requested Status
Jeroen T. Vermeulen (community) Approve
Review via email: mp+189250@code.launchpad.net

Commit message

Fix the add-new-interface UI so that it doesn't blow up when the nodegroup is already 'managed' and one is trying to add another 'managed' interface.

Description of the change

Instead of using a custom save() method on NodeGroupInterfaceForm, simply use Django's built-in 'instance' parameter to give the form an instance initialized with the right nodegroup. It means that the instance's nodegroup is set right from the start (as opposed to just before save() is called). This allows Django to perform the model validation (when the existence of another managed interface is checked) as part of the form validation.

To post a comment you must log in.
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

Looks sensible. In src/maasserver/views/settings_clusters.py, is there any need for get_form_kwargs() to check whether 'instance' might already be set?

review: Approve
Revision history for this message
Raphaël Badin (rvb) wrote :

> Looks sensible. In src/maasserver/views/settings_clusters.py, is there any
> need for get_form_kwargs() to check whether 'instance' might already be set?

Well, not really, this is a method on ClusterInterfaceCreate(). That view is there to handle the *creation* of an interface so it's guaranteed that no instance will be there already. I'll put an assertion.

Thanks for the review!

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-09-25 12:34:45 +0000
3+++ src/maasserver/api.py 2013-10-04 10:46:18 +0000
4@@ -1659,10 +1659,10 @@
5 :type ip_range_high: basestring (IP Address)
6 """
7 nodegroup = get_object_or_404(NodeGroup, uuid=uuid)
8- form = NodeGroupInterfaceForm(request.data)
9+ instance = NodeGroupInterface(nodegroup=nodegroup)
10+ form = NodeGroupInterfaceForm(request.data, instance=instance)
11 if form.is_valid():
12- return form.save(
13- nodegroup=nodegroup)
14+ return form.save()
15 else:
16 raise ValidationError(form.errors)
17
18
19=== modified file 'src/maasserver/forms.py'
20--- src/maasserver/forms.py 2013-09-16 05:13:13 +0000
21+++ src/maasserver/forms.py 2013-10-04 10:46:18 +0000
22@@ -674,14 +674,6 @@
23 'ip_range_high',
24 )
25
26- def save(self, nodegroup=None, commit=True, *args, **kwargs):
27- interface = super(NodeGroupInterfaceForm, self).save(commit=False)
28- if nodegroup is not None:
29- interface.nodegroup = nodegroup
30- if commit:
31- interface.save(*args, **kwargs)
32- return interface
33-
34
35 INTERFACES_VALIDATION_ERROR_MESSAGE = (
36 "Invalid json value: should be a list of dictionaries, each containing "
37@@ -766,8 +758,9 @@
38 def save(self):
39 nodegroup = super(NodeGroupWithInterfacesForm, self).save()
40 for interface in self.cleaned_data['interfaces']:
41- form = NodeGroupInterfaceForm(data=interface)
42- form.save(nodegroup=nodegroup)
43+ instance = NodeGroupInterface(nodegroup=nodegroup)
44+ form = NodeGroupInterfaceForm(data=interface, instance=instance)
45+ form.save()
46 if self.status is not None:
47 nodegroup.status = self.status
48 nodegroup.save()
49
50=== modified file 'src/maasserver/tests/test_forms.py'
51--- src/maasserver/tests/test_forms.py 2013-09-16 05:13:13 +0000
52+++ src/maasserver/tests/test_forms.py 2013-10-04 10:46:18 +0000
53@@ -673,14 +673,6 @@
54
55 class TestNodeGroupInterfaceForm(MAASServerTestCase):
56
57- def test_NodeGroupInterfaceForm_save_sets_nodegroup(self):
58- nodegroup = factory.make_node_group(
59- management=NODEGROUPINTERFACE_MANAGEMENT.UNMANAGED)
60- form = NodeGroupInterfaceForm(data=make_interface_settings())
61- self.assertTrue(form.is_valid(), form._errors)
62- interface = form.save(nodegroup=nodegroup)
63- self.assertEqual(nodegroup, interface.nodegroup)
64-
65 def test_NodeGroupInterfaceForm_validates_parameters(self):
66 form = NodeGroupInterfaceForm(data={'ip': factory.getRandomString()})
67 self.assertFalse(form.is_valid())
68@@ -692,9 +684,10 @@
69 settings['management'] = NODEGROUPINTERFACE_MANAGEMENT.UNMANAGED
70 for field_name in nullable_fields:
71 del settings[field_name]
72- form = NodeGroupInterfaceForm(data=settings)
73 nodegroup = factory.make_node_group()
74- interface = form.save(nodegroup=nodegroup)
75+ form = NodeGroupInterfaceForm(
76+ data=settings, instance=NodeGroupInterface(nodegroup=nodegroup))
77+ interface = form.save()
78 field_values = [
79 getattr(interface, field_name) for field_name in nullable_fields]
80 self.assertThat(field_values, AllMatch(Equals('')))
81
82=== modified file 'src/maasserver/tests/test_views_settings_clusters.py'
83--- src/maasserver/tests/test_views_settings_clusters.py 2013-02-08 17:16:07 +0000
84+++ src/maasserver/tests/test_views_settings_clusters.py 2013-10-04 10:46:18 +0000
85@@ -198,6 +198,21 @@
86 reload_object(interface),
87 MatchesStructure.byEquality(**data))
88
89+ def test_rejects_interface_creation_if_cluster_already_managed(self):
90+ nodegroup = factory.make_node_group(
91+ management=NODEGROUPINTERFACE_MANAGEMENT.DHCP)
92+ create_link = reverse(
93+ 'cluster-interface-create', args=[nodegroup.uuid])
94+ # nodegroup already has a 'managed' interface, try adding another
95+ # one, also 'managed'.
96+ data = factory.get_interface_fields(
97+ management=NODEGROUPINTERFACE_MANAGEMENT.DHCP)
98+ response = self.client.post(create_link, data)
99+ self.assertEqual(httplib.OK, response.status_code)
100+ error_message = (
101+ "Another managed interface already exists for this cluster.")
102+ self.assertThat(response.content, Contains(error_message))
103+
104
105 # XXX: rvb 2012-10-08 bug=1063881: apache transforms '//' into '/' in
106 # the urls it passes around and this happens when an interface has an empty
107
108=== modified file 'src/maasserver/views/settings_clusters.py'
109--- src/maasserver/views/settings_clusters.py 2012-10-15 09:32:06 +0000
110+++ src/maasserver/views/settings_clusters.py 2013-10-04 10:46:18 +0000
111@@ -126,12 +126,18 @@
112 form_class = NodeGroupInterfaceForm
113 context_object_name = 'interface'
114
115+ def get_form_kwargs(self):
116+ kwargs = super(ClusterInterfaceCreate, self).get_form_kwargs()
117+ assert kwargs.get('instance', None) is None
118+ kwargs['instance'] = NodeGroupInterface(nodegroup=self.get_nodegroup())
119+ return kwargs
120+
121 def get_success_url(self):
122 uuid = self.kwargs.get('uuid', None)
123 return reverse('cluster-edit', args=[uuid])
124
125 def form_valid(self, form):
126- self.object = form.save(nodegroup=self.get_nodegroup())
127+ self.object = form.save()
128 messages.info(self.request, "Interface created.")
129 return super(ClusterInterfaceCreate, self).form_valid(form)
130