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
=== modified file 'src/maasserver/api.py'
--- src/maasserver/api.py 2013-09-25 12:34:45 +0000
+++ src/maasserver/api.py 2013-10-04 10:46:18 +0000
@@ -1659,10 +1659,10 @@
1659 :type ip_range_high: basestring (IP Address)1659 :type ip_range_high: basestring (IP Address)
1660 """1660 """
1661 nodegroup = get_object_or_404(NodeGroup, uuid=uuid)1661 nodegroup = get_object_or_404(NodeGroup, uuid=uuid)
1662 form = NodeGroupInterfaceForm(request.data)1662 instance = NodeGroupInterface(nodegroup=nodegroup)
1663 form = NodeGroupInterfaceForm(request.data, instance=instance)
1663 if form.is_valid():1664 if form.is_valid():
1664 return form.save(1665 return form.save()
1665 nodegroup=nodegroup)
1666 else:1666 else:
1667 raise ValidationError(form.errors)1667 raise ValidationError(form.errors)
16681668
16691669
=== modified file 'src/maasserver/forms.py'
--- src/maasserver/forms.py 2013-09-16 05:13:13 +0000
+++ src/maasserver/forms.py 2013-10-04 10:46:18 +0000
@@ -674,14 +674,6 @@
674 'ip_range_high',674 'ip_range_high',
675 )675 )
676676
677 def save(self, nodegroup=None, commit=True, *args, **kwargs):
678 interface = super(NodeGroupInterfaceForm, self).save(commit=False)
679 if nodegroup is not None:
680 interface.nodegroup = nodegroup
681 if commit:
682 interface.save(*args, **kwargs)
683 return interface
684
685677
686INTERFACES_VALIDATION_ERROR_MESSAGE = (678INTERFACES_VALIDATION_ERROR_MESSAGE = (
687 "Invalid json value: should be a list of dictionaries, each containing "679 "Invalid json value: should be a list of dictionaries, each containing "
@@ -766,8 +758,9 @@
766 def save(self):758 def save(self):
767 nodegroup = super(NodeGroupWithInterfacesForm, self).save()759 nodegroup = super(NodeGroupWithInterfacesForm, self).save()
768 for interface in self.cleaned_data['interfaces']:760 for interface in self.cleaned_data['interfaces']:
769 form = NodeGroupInterfaceForm(data=interface)761 instance = NodeGroupInterface(nodegroup=nodegroup)
770 form.save(nodegroup=nodegroup)762 form = NodeGroupInterfaceForm(data=interface, instance=instance)
763 form.save()
771 if self.status is not None:764 if self.status is not None:
772 nodegroup.status = self.status765 nodegroup.status = self.status
773 nodegroup.save()766 nodegroup.save()
774767
=== modified file 'src/maasserver/tests/test_forms.py'
--- src/maasserver/tests/test_forms.py 2013-09-16 05:13:13 +0000
+++ src/maasserver/tests/test_forms.py 2013-10-04 10:46:18 +0000
@@ -673,14 +673,6 @@
673673
674class TestNodeGroupInterfaceForm(MAASServerTestCase):674class TestNodeGroupInterfaceForm(MAASServerTestCase):
675675
676 def test_NodeGroupInterfaceForm_save_sets_nodegroup(self):
677 nodegroup = factory.make_node_group(
678 management=NODEGROUPINTERFACE_MANAGEMENT.UNMANAGED)
679 form = NodeGroupInterfaceForm(data=make_interface_settings())
680 self.assertTrue(form.is_valid(), form._errors)
681 interface = form.save(nodegroup=nodegroup)
682 self.assertEqual(nodegroup, interface.nodegroup)
683
684 def test_NodeGroupInterfaceForm_validates_parameters(self):676 def test_NodeGroupInterfaceForm_validates_parameters(self):
685 form = NodeGroupInterfaceForm(data={'ip': factory.getRandomString()})677 form = NodeGroupInterfaceForm(data={'ip': factory.getRandomString()})
686 self.assertFalse(form.is_valid())678 self.assertFalse(form.is_valid())
@@ -692,9 +684,10 @@
692 settings['management'] = NODEGROUPINTERFACE_MANAGEMENT.UNMANAGED684 settings['management'] = NODEGROUPINTERFACE_MANAGEMENT.UNMANAGED
693 for field_name in nullable_fields:685 for field_name in nullable_fields:
694 del settings[field_name]686 del settings[field_name]
695 form = NodeGroupInterfaceForm(data=settings)
696 nodegroup = factory.make_node_group()687 nodegroup = factory.make_node_group()
697 interface = form.save(nodegroup=nodegroup)688 form = NodeGroupInterfaceForm(
689 data=settings, instance=NodeGroupInterface(nodegroup=nodegroup))
690 interface = form.save()
698 field_values = [691 field_values = [
699 getattr(interface, field_name) for field_name in nullable_fields]692 getattr(interface, field_name) for field_name in nullable_fields]
700 self.assertThat(field_values, AllMatch(Equals('')))693 self.assertThat(field_values, AllMatch(Equals('')))
701694
=== modified file 'src/maasserver/tests/test_views_settings_clusters.py'
--- src/maasserver/tests/test_views_settings_clusters.py 2013-02-08 17:16:07 +0000
+++ src/maasserver/tests/test_views_settings_clusters.py 2013-10-04 10:46:18 +0000
@@ -198,6 +198,21 @@
198 reload_object(interface),198 reload_object(interface),
199 MatchesStructure.byEquality(**data))199 MatchesStructure.byEquality(**data))
200200
201 def test_rejects_interface_creation_if_cluster_already_managed(self):
202 nodegroup = factory.make_node_group(
203 management=NODEGROUPINTERFACE_MANAGEMENT.DHCP)
204 create_link = reverse(
205 'cluster-interface-create', args=[nodegroup.uuid])
206 # nodegroup already has a 'managed' interface, try adding another
207 # one, also 'managed'.
208 data = factory.get_interface_fields(
209 management=NODEGROUPINTERFACE_MANAGEMENT.DHCP)
210 response = self.client.post(create_link, data)
211 self.assertEqual(httplib.OK, response.status_code)
212 error_message = (
213 "Another managed interface already exists for this cluster.")
214 self.assertThat(response.content, Contains(error_message))
215
201216
202# XXX: rvb 2012-10-08 bug=1063881: apache transforms '//' into '/' in217# XXX: rvb 2012-10-08 bug=1063881: apache transforms '//' into '/' in
203# the urls it passes around and this happens when an interface has an empty218# the urls it passes around and this happens when an interface has an empty
204219
=== modified file 'src/maasserver/views/settings_clusters.py'
--- src/maasserver/views/settings_clusters.py 2012-10-15 09:32:06 +0000
+++ src/maasserver/views/settings_clusters.py 2013-10-04 10:46:18 +0000
@@ -126,12 +126,18 @@
126 form_class = NodeGroupInterfaceForm126 form_class = NodeGroupInterfaceForm
127 context_object_name = 'interface'127 context_object_name = 'interface'
128128
129 def get_form_kwargs(self):
130 kwargs = super(ClusterInterfaceCreate, self).get_form_kwargs()
131 assert kwargs.get('instance', None) is None
132 kwargs['instance'] = NodeGroupInterface(nodegroup=self.get_nodegroup())
133 return kwargs
134
129 def get_success_url(self):135 def get_success_url(self):
130 uuid = self.kwargs.get('uuid', None)136 uuid = self.kwargs.get('uuid', None)
131 return reverse('cluster-edit', args=[uuid])137 return reverse('cluster-edit', args=[uuid])
132138
133 def form_valid(self, form):139 def form_valid(self, form):
134 self.object = form.save(nodegroup=self.get_nodegroup())140 self.object = form.save()
135 messages.info(self.request, "Interface created.")141 messages.info(self.request, "Interface created.")
136 return super(ClusterInterfaceCreate, self).form_valid(form)142 return super(ClusterInterfaceCreate, self).form_valid(form)
137143