launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #12511
[Merge] lp:~rvb/maas/first-cluster-registration into lp:maas
Raphaël Badin has proposed merging lp:~rvb/maas/first-cluster-registration into lp:maas with lp:~rvb/maas/ensure-master-takes-first as a prerequisite.
Commit message:
Change the nodegroup registration API method: when a cluster controller registers, if the master nodegroup still has it's UUID not set to a proper UUID, link this cluster controller to the master nodegroup.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~rvb/maas/first-cluster-registration/+merge/126501
Change the nodegroup registration API method: when a cluster controller registers, if the master nodegroup still has it's UUID not set to a proper UUID, link this cluster controller to the master nodegroup.
= Pre-imp =
This was discussed with Julian and Jeroen.
--
https://code.launchpad.net/~rvb/maas/first-cluster-registration/+merge/126501
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~rvb/maas/first-cluster-registration into lp:maas.
=== modified file 'src/maasserver/api.py'
--- src/maasserver/api.py 2012-09-26 10:00:14 +0000
+++ src/maasserver/api.py 2012-09-26 16:53:22 +0000
@@ -911,6 +911,14 @@
return ('files_handler', [])
+def get_celery_credentials():
+ """Return the credentials needed to connect to the broker."""
+ celery_conf = app_or_default().conf
+ return {
+ 'BROKER_URL': celery_conf.BROKER_URL,
+ }
+
+
DISPLAYED_NODEGROUP_FIELDS = ('uuid', 'status', 'name')
@@ -974,24 +982,33 @@
uuid = get_mandatory_param(request.data, 'uuid')
existing_nodegroup = get_one(NodeGroup.objects.filter(uuid=uuid))
if existing_nodegroup is None:
- # This nodegroup (identified by its uuid), does not exist yet,
- # create it if the data validates.
- form = NodeGroupWithInterfacesForm(request.data)
- if form.is_valid():
- form.save()
- return HttpResponse(
- "Cluster registered. Awaiting admin approval.",
- status=httplib.ACCEPTED)
+ master = NodeGroup.objects.ensure_master()
+ # Does master.uuid look like it's a proper uuid?
+ if len(master.uuid) != 36:
+ # Master nodegroup not yet configured, configure it.
+ form = NodeGroupWithInterfacesForm(
+ data=request.data, instance=master)
+ if form.is_valid():
+ form.save()
+ return get_celery_credentials()
+ else:
+ raise ValidationError(form.errors)
else:
- raise ValidationError(form.errors)
+ # This nodegroup (identified by its uuid), does not exist yet,
+ # create it if the data validates.
+ form = NodeGroupWithInterfacesForm(
+ data=request.data, status=NODEGROUP_STATUS.PENDING)
+ if form.is_valid():
+ form.save()
+ return HttpResponse(
+ "Cluster registered. Awaiting admin approval.",
+ status=httplib.ACCEPTED)
+ else:
+ raise ValidationError(form.errors)
else:
if existing_nodegroup.status == NODEGROUP_STATUS.ACCEPTED:
# The nodegroup exists and is validated, return the RabbitMQ
- # credentials as JSON.
- celery_conf = app_or_default().conf
- return {
- 'BROKER_URL': celery_conf.BROKER_URL,
- }
+ return get_celery_credentials()
elif existing_nodegroup.status == NODEGROUP_STATUS.REJECTED:
raise PermissionDenied('Rejected cluster.')
elif existing_nodegroup.status == NODEGROUP_STATUS.PENDING:
=== modified file 'src/maasserver/forms.py'
--- src/maasserver/forms.py 2012-09-23 14:14:20 +0000
+++ src/maasserver/forms.py 2012-09-26 16:53:22 +0000
@@ -59,7 +59,6 @@
DISTRO_SERIES_CHOICES,
NODE_AFTER_COMMISSIONING_ACTION,
NODE_AFTER_COMMISSIONING_ACTION_CHOICES,
- NODEGROUP_STATUS,
NODEGROUPINTERFACE_MANAGEMENT,
NODEGROUPINTERFACE_MANAGEMENT_CHOICES,
)
@@ -688,7 +687,7 @@
class NodeGroupWithInterfacesForm(ModelForm):
- """Create a pending NodeGroup with unmanaged interfaces."""
+ """Create a NodeGroup with unmanaged interfaces."""
interfaces = forms.CharField(required=False)
@@ -699,6 +698,10 @@
'uuid',
)
+ def __init__(self, status=None, *args, **kwargs):
+ super(NodeGroupWithInterfacesForm, self).__init__(*args, **kwargs)
+ self.status = status
+
def clean_interfaces(self):
data = self.cleaned_data['interfaces']
# Stop here if the data is empty.
@@ -741,9 +744,9 @@
for interface in self.cleaned_data['interfaces']:
form = NodeGroupInterfaceForm(data=interface)
form.save(nodegroup=nodegroup)
- # Set the nodegroup to be 'PENDING'.
- nodegroup.status = NODEGROUP_STATUS.PENDING
- nodegroup.save()
+ if self.status is not None:
+ nodegroup.status = self.status
+ nodegroup.save()
return nodegroup
=== modified file 'src/maasserver/tests/test_api.py'
--- src/maasserver/tests/test_api.py 2012-09-26 16:53:22 +0000
+++ src/maasserver/tests/test_api.py 2012-09-26 16:53:22 +0000
@@ -2705,6 +2705,11 @@
('celery', FixtureResource(CeleryFixture())),
)
+ def create_configured_master(self):
+ master = NodeGroup.objects.ensure_master()
+ master.uuid = factory.getRandomUUID()
+ master.save()
+
def test_refresh_calls_refresh_worker(self):
nodegroup = factory.make_node_group()
response = self.client.post(
@@ -2723,6 +2728,7 @@
(response.status_code, response.content))
def test_register_nodegroup_creates_nodegroup_and_interfaces(self):
+ self.create_configured_master()
name = factory.make_name('name')
uuid = factory.getRandomUUID()
interface = make_interface_settings()
@@ -2747,7 +2753,45 @@
# validated by an admin.
self.assertEqual(httplib.ACCEPTED, response.status_code)
+ def test_register_nodegroup_returns_credentials_if_master(self):
+ name = factory.make_name('name')
+ uuid = factory.getRandomUUID()
+ fake_broker_url = factory.make_name('fake-broker_url')
+ celery_conf = app_or_default().conf
+ self.patch(celery_conf, 'BROKER_URL', fake_broker_url)
+ response = self.client.post(
+ reverse('nodegroups_handler'),
+ {
+ 'op': 'register',
+ 'name': name,
+ 'uuid': uuid,
+ })
+ self.assertEqual(httplib.OK, response.status_code, response)
+ parsed_result = json.loads(response.content)
+ self.assertEqual(
+ ({'BROKER_URL': fake_broker_url}, uuid),
+ (parsed_result, NodeGroup.objects.ensure_master().uuid))
+
+ def test_register_nodegroup_configures_master_if_unconfigured(self):
+ name = factory.make_name('name')
+ uuid = factory.getRandomUUID()
+ interface = make_interface_settings()
+ self.client.post(
+ reverse('nodegroups_handler'),
+ {
+ 'op': 'register',
+ 'name': name,
+ 'uuid': uuid,
+ 'interfaces': json.dumps([interface]),
+ })
+ master = NodeGroup.objects.ensure_master()
+ self.assertThat(
+ master.nodegroupinterface_set.all()[0],
+ MatchesStructure.byEquality(**interface))
+ self.assertEqual(NODEGROUP_STATUS.ACCEPTED, master.status)
+
def test_register_accepts_only_one_managed_interface(self):
+ self.create_configured_master()
name = factory.make_name('name')
uuid = factory.getRandomUUID()
# This will try to create 2 "managed" interfaces.
@@ -2774,6 +2818,7 @@
(response.status_code, json.loads(response.content)))
def test_register_nodegroup_validates_data(self):
+ self.create_configured_master()
response = self.client.post(
reverse('nodegroups_handler'),
{
=== modified file 'src/maasserver/tests/test_forms.py'
--- src/maasserver/tests/test_forms.py 2012-09-21 07:09:00 +0000
+++ src/maasserver/tests/test_forms.py 2012-09-26 16:53:22 +0000
@@ -673,6 +673,16 @@
nodegroup.nodegroupinterface_set.count(),
))
+ def test_NodeGroupWithInterfacesForm_creates_nodegroup_with_status(self):
+ name = factory.make_name('name')
+ uuid = factory.getRandomUUID()
+ form = NodeGroupWithInterfacesForm(
+ status=NODEGROUP_STATUS.ACCEPTED,
+ data={'name': name, 'uuid': uuid})
+ self.assertTrue(form.is_valid(), form._errors)
+ nodegroup = form.save()
+ self.assertEqual(NODEGROUP_STATUS.ACCEPTED, nodegroup.status)
+
def test_NodeGroupWithInterfacesForm_validates_parameters(self):
name = factory.make_name('name')
too_long_uuid = 'test' * 30
Follow ups