← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~allenap/maas/anon-power-setting into lp:maas

 

Gavin Panella has proposed merging lp:~allenap/maas/anon-power-setting into lp:maas.

Commit message:
Allows power parameters to be supplied at enlistment.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #1055662 in MAAS: "Anonymous API access to update power_type, power_settings"
  https://bugs.launchpad.net/maas/+bug/1055662

For more details, see:
https://code.launchpad.net/~allenap/maas/anon-power-setting/+merge/128127
-- 
https://code.launchpad.net/~allenap/maas/anon-power-setting/+merge/128127
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~allenap/maas/anon-power-setting into lp:maas.
=== modified file 'src/maasserver/api.py'
--- src/maasserver/api.py	2012-10-04 10:08:26 +0000
+++ src/maasserver/api.py	2012-10-04 22:25:25 +0000
@@ -158,6 +158,7 @@
     compose_preseed_url,
     )
 from maasserver.server_address import get_maas_facing_server_address
+from maasserver.utils import map_enum
 from maasserver.utils.orm import get_one
 from piston.handler import (
     AnonymousBaseHandler,
@@ -167,6 +168,7 @@
 from piston.models import Token
 from piston.resource import Resource
 from piston.utils import rc
+from provisioningserver.enum import POWER_TYPE
 from provisioningserver.kernel_opts import KernelParameters
 
 
@@ -418,6 +420,29 @@
     )
 
 
+def store_node_power_parameters(node, request):
+    """Store power parameters in request.
+
+    The parameters should be JSON, passed with key `power_parameters`.
+    """
+    type = request.POST.get("power_type", None)
+    if type is None:
+        return
+
+    params = request.POST.get("power_parameters", None)
+
+    type_dict = map_enum(POWER_TYPE)
+    if type.upper() not in type_dict:
+        raise MAASAPIBadRequest("Bad power_type '%s'" % type)
+    node.power_type = type_dict[type.upper()]
+
+    try:
+        node.power_parameters = json.loads(params)
+    except ValueError:
+        raise MAASAPIBadRequest("Failed to parse json power_parameters")
+    node.save()
+
+
 class NodeHandler(OperationsHandler):
     """Manage individual Nodes."""
     create = None  # Disable create.
@@ -586,7 +611,10 @@
     Form = get_node_create_form(request.user)
     form = Form(altered_query_data)
     if form.is_valid():
-        return form.save()
+        node = form.save()
+        # Hack in the power parameters here.
+        store_node_power_parameters(node, request)
+        return node
     else:
         raise ValidationError(form.errors)
 

=== modified file 'src/maasserver/tests/test_api.py'
--- src/maasserver/tests/test_api.py	2012-10-04 12:08:36 +0000
+++ src/maasserver/tests/test_api.py	2012-10-04 22:25:25 +0000
@@ -289,6 +289,32 @@
         [diane] = Node.objects.filter(hostname='diane')
         self.assertEqual(architecture, diane.architecture)
 
+    def test_POST_new_creates_node_with_power_parameters(self):
+        # We're setting power parameters so we disable start_commissioning to
+        # prevent anything from attempting to issue power instructions.
+        self.patch(Node, "start_commissioning")
+        hostname = factory.make_name("hostname")
+        architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES)
+        power_type = POWER_TYPE.IPMI
+        power_parameters = {
+            "power_user": factory.make_name("power-user"),
+            "power_pass": factory.make_name("power-pass"),
+            }
+        response = self.client.post(
+            self.get_uri('nodes/'),
+            {
+                'op': 'new',
+                'hostname': hostname,
+                'architecture': architecture,
+                'mac_addresses': factory.getRandomMACAddress(),
+                'power_parameters': json.dumps(power_parameters),
+                'power_type': power_type,
+            })
+        self.assertEqual(httplib.OK, response.status_code)
+        [node] = Node.objects.filter(hostname=hostname)
+        self.assertEqual(power_parameters, node.power_parameters)
+        self.assertEqual(power_type, node.power_type)
+
     def test_POST_new_creates_node_with_arch_only(self):
         architecture = factory.getRandomChoice(
             [choice for choice in ARCHITECTURE_CHOICES

=== modified file 'src/metadataserver/api.py'
--- src/metadataserver/api.py	2012-10-04 09:53:04 +0000
+++ src/metadataserver/api.py	2012-10-04 22:25:25 +0000
@@ -18,8 +18,6 @@
     'VersionIndexHandler',
     ]
 
-import json
-
 from django.conf import settings
 from django.core.exceptions import PermissionDenied
 from django.http import HttpResponse
@@ -29,6 +27,7 @@
     get_mandatory_param,
     operation,
     OperationsHandler,
+    store_node_power_parameters,
     )
 from maasserver.enum import (
     NODE_STATUS,
@@ -49,7 +48,6 @@
     get_enlist_userdata,
     get_preseed,
     )
-from maasserver.utils import map_enum
 from maasserver.utils.orm import get_one
 from metadataserver.models import (
     NodeCommissionResult,
@@ -57,7 +55,6 @@
     NodeUserData,
     )
 from piston.utils import rc
-from provisioningserver.enum import POWER_TYPE
 
 
 class UnknownMetadataVersion(MAASAPINotFound):
@@ -188,25 +185,6 @@
             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)
-        if type is None:
-            return
-
-        params = request.POST.get("power_parameters", None)
-
-        type_dict = map_enum(POWER_TYPE)
-        if type.upper() not in type_dict:
-            raise MAASAPIBadRequest("Bad power_type '%s'" % type)
-        node.power_type = type_dict[type.upper()]
-
-        try:
-            node.power_parameters = json.loads(params)
-        except ValueError:
-            raise MAASAPIBadRequest("Failed to parse json power_parameters")
-        node.save()
-
     @operation(idempotent=False)
     def signal(self, request, version=None, mac=None):
         """Signal commissioning status.
@@ -243,7 +221,7 @@
             return rc.ALL_OK
 
         self._store_commissioning_results(node, request)
-        self._store_power_parameters(node, request)
+        store_node_power_parameters(node, request)
 
         target_status = self.signaling_statuses.get(status)
         if target_status in (None, node.status):