← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~julian-edwards/maas/enlist-power-params into lp:maas

 

Julian Edwards has proposed merging lp:~julian-edwards/maas/enlist-power-params into lp:maas.

Commit message:
Allow the commissioning "signal" parameter to take optional power parameters.

This means the BMC discovery at commissioning will be able to set the parameters up thereby allowing MAAS to power up the machine later.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~julian-edwards/maas/enlist-power-params/+merge/126619
-- 
https://code.launchpad.net/~julian-edwards/maas/enlist-power-params/+merge/126619
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~julian-edwards/maas/enlist-power-params into lp:maas.
=== modified file 'src/metadataserver/api.py'
--- src/metadataserver/api.py	2012-09-24 11:44:49 +0000
+++ src/metadataserver/api.py	2012-09-27 07:35:26 +0000
@@ -47,6 +47,7 @@
     get_enlist_userdata,
     get_preseed,
     )
+from maasserver.utils import map_enum
 from maasserver.utils.orm import get_one
 from metadataserver.models import (
     NodeCommissionResult,
@@ -55,6 +56,7 @@
     )
 from piston.handler import BaseHandler
 from piston.utils import rc
+from provisioningserver.enum import POWER_TYPE
 
 
 class UnknownMetadataVersion(MAASAPINotFound):
@@ -186,6 +188,31 @@
             contents = raw_content.decode('utf-8')
             NodeCommissionResult.objects.store_data(node, name, contents)
 
+    def _store_power_parameters(self, node, request):
+        """Store power parameters passed back in commissioning result."""
+        type = request.POST.get("power_type", None)
+        address = request.POST.get("power_address", None)
+        user = request.POST.get("power_user", None)
+        password = request.POST.get("power_pass", None)
+
+        if type is None:
+            return
+
+        type_dict = map_enum(POWER_TYPE)
+        if type.upper() not in type_dict:
+            raise MAASAPIBadRequest("Bad power_type '%s'" % type)
+        if password is None:
+            raise MAASAPIBadRequest("Missing power_pass parameter")
+        if user is None:
+            raise MAASAPIBadRequest("Missing power_user parameter")
+        if address is None:
+            raise MAASAPIBadRequest("Missing power_address parameter")
+
+        node.power_parameters = dict(
+            power_type=type, power_address=address, power_user=user,
+            power_pass=password)
+        node.save()
+
     @api_exported('POST')
     def signal(self, request, version=None, mac=None):
         """Signal commissioning status.
@@ -222,6 +249,7 @@
             return rc.ALL_OK
 
         self._store_commissioning_results(node, request)
+        self._store_power_parameters(node, request)
 
         target_status = self.signaling_statuses.get(status)
         if target_status in (None, node.status):

=== modified file 'src/metadataserver/tests/test_api.py'
--- src/metadataserver/tests/test_api.py	2012-09-25 12:15:46 +0000
+++ src/metadataserver/tests/test_api.py	2012-09-27 07:35:26 +0000
@@ -504,6 +504,75 @@
         self.assertEqual(xmlbytes, node.hardware_details)
         self.assertEqual(0, node.memory)
 
+    def test_signal_refuses_bad_power_type(self):
+        node = factory.make_node(status=NODE_STATUS.COMMISSIONING)
+        client = self.make_node_client(node=node)
+        response = self.call_signal(client, power_type="foo")
+        self.assertEqual(
+            (httplib.BAD_REQUEST, "Bad power_type 'foo'"),
+            (response.status_code, response.content))
+
+    def test_signal_requires_power_pass(self):
+        node = factory.make_node(status=NODE_STATUS.COMMISSIONING)
+        client = self.make_node_client(node=node)
+        response = self.call_signal(
+            client, power_type="IPMI",
+            power_address=factory.getRandomString(),
+            power_user=factory.getRandomString())
+        self.assertEqual(
+            (httplib.BAD_REQUEST, "Missing power_pass parameter"),
+            (response.status_code, response.content))
+
+    def test_signal_requires_power_user(self):
+        node = factory.make_node(status=NODE_STATUS.COMMISSIONING)
+        client = self.make_node_client(node=node)
+        response = self.call_signal(
+            client, power_type="IPMI",
+            power_address=factory.getRandomString(),
+            power_pass=factory.getRandomString())
+        self.assertEqual(
+            (httplib.BAD_REQUEST, "Missing power_user parameter"),
+            (response.status_code, response.content))
+
+    def test_signal_requires_power_address(self):
+        node = factory.make_node(status=NODE_STATUS.COMMISSIONING)
+        client = self.make_node_client(node=node)
+        response = self.call_signal(
+            client, power_type="IPMI",
+            power_user=factory.getRandomString(),
+            power_pass=factory.getRandomString())
+        self.assertEqual(
+            (httplib.BAD_REQUEST, "Missing power_address parameter"),
+            (response.status_code, response.content))
+
+    def test_signal_power_type_stores_params(self):
+        node = factory.make_node(status=NODE_STATUS.COMMISSIONING)
+        client = self.make_node_client(node=node)
+        params = dict(
+            power_address=factory.getRandomString(),
+            power_user=factory.getRandomString(),
+            power_pass=factory.getRandomString(),
+            power_type="IPMI")
+        response = self.call_signal(client, **params)
+        self.assertEqual(httplib.OK, response.status_code)
+        node = reload_object(node)
+        self.assertEqual(
+            params, node.power_parameters)
+
+    def test_signal_power_type_lower_case_works(self):
+        node = factory.make_node(status=NODE_STATUS.COMMISSIONING)
+        client = self.make_node_client(node=node)
+        params = dict(
+            power_address=factory.getRandomString(),
+            power_user=factory.getRandomString(),
+            power_pass=factory.getRandomString(),
+            power_type="ipmi")
+        response = self.call_signal(client, **params)
+        self.assertEqual(httplib.OK, response.status_code)
+        node = reload_object(node)
+        self.assertEqual(
+            params, node.power_parameters)
+
     def test_api_retrieves_node_metadata_by_mac(self):
         mac = factory.make_mac_address()
         url = reverse(


Follow ups