← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~jtv/maas/preseed-url into lp:maas

 

Jeroen T. Vermeulen has proposed merging lp:~jtv/maas/preseed-url into lp:maas.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~jtv/maas/preseed-url/+merge/116212

Based on discussion with Gavin, who banged his head against this problem before.  Each PXE config file provides kernel options.  Those kernel options should provide an “auto url” parameter that links to preseed information for the node to use.

As you can see I opted to do this by appending the new kernel option to the “append” parameter that goes into the template.  That's why the config template is not affected: it already has a place for this.  We may want to refine this at some point; but then again, we may not.


Jeroen
-- 
https://code.launchpad.net/~jtv/maas/preseed-url/+merge/116212
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~jtv/maas/preseed-url into lp:maas.
=== modified file 'src/maasserver/api.py'
--- src/maasserver/api.py	2012-07-12 12:33:57 +0000
+++ src/maasserver/api.py	2012-07-23 07:49:22 +0000
@@ -85,6 +85,7 @@
     PermissionDenied,
     ValidationError,
     )
+from django.core.urlresolvers import reverse
 from django.forms.models import model_to_dict
 from django.http import (
     HttpResponse,
@@ -1026,6 +1027,33 @@
         context_instance=RequestContext(request))
 
 
+def compose_enlistment_preseed_url():
+    """Compose enlistment preseed URL."""
+    # Always uses the latest version of the metadata API.
+    version = 'latest'
+    return "%s?op=get_enlist_preseed" % reverse(
+        'metadata-enlist-preseed', args=[version])
+
+
+def compose_preseed_url(node):
+    """Compose a metadata URL for `node`'s preseed data."""
+    # Always uses the latest version of the metadata API.
+    version = 'latest'
+    return "%s?op=get_preseed" % reverse(
+        'metadata-node-by-id', args=[version, node.system_id])
+
+
+def compose_preseed_kernel_opt(mac):
+    """Compose a kernel option for preseed URL for node that owns `mac`."""
+    macaddress_match = MACAddress.objects.filter(mac_address=mac)
+    if len(macaddress_match) == 0:
+        preseed_url = compose_enlistment_preseed_url()
+    else:
+        [macaddress] = macaddress_match
+        preseed_url = compose_preseed_url(macaddress.node)
+    return "auto url=%s" % preseed_url
+
+
 def pxeconfig(request):
     """Get the PXE configuration given a node's details.
 
@@ -1037,18 +1065,22 @@
     :param kernelimage: The path to the kernel in the TFTP server
     :param append: Kernel parameters to append.
     """
+    menutitle = get_mandatory_param(request.GET, 'menutitle')
+    kernelimage = get_mandatory_param(request.GET, 'kernelimage')
+    append = get_mandatory_param(request.GET, 'append')
     arch = get_mandatory_param(request.GET, 'arch')
     subarch = request.GET.get('subarch', None)
     mac = request.GET.get('mac', None)
     config = PXEConfig(arch, subarch, mac)
-    # Rendering parameters.
-    menutitle = get_mandatory_param(request.GET, 'menutitle')
-    kernelimage = get_mandatory_param(request.GET, 'kernelimage')
-    append = get_mandatory_param(request.GET, 'append')
+
+    # In addition to the "append" parameter, also add a URL for the
+    # node's preseed to the kernel command line.
+    append = "%s %s" % (append, compose_preseed_kernel_opt(mac))
+
     try:
         return HttpResponse(
             config.get_config(
                 menutitle=menutitle, kernelimage=kernelimage, append=append),
             content_type="text/plain; charset=utf-8")
-    except PXEConfigFail, e:
+    except PXEConfigFail as e:
         raise ValidationError(e.message)

=== modified file 'src/maasserver/tests/test_api.py'
--- src/maasserver/tests/test_api.py	2012-07-12 12:33:57 +0000
+++ src/maasserver/tests/test_api.py	2012-07-23 07:49:22 +0000
@@ -59,6 +59,10 @@
     create_auth_token,
     get_auth_tokens,
     )
+from maasserver.preseed import (
+    get_enlist_preseed,
+    get_preseed,
+    )
 from maasserver.testing import (
     reload_object,
     reload_objects,
@@ -2226,7 +2230,7 @@
         return {
                 'arch': "armhf",
                 'subarch': "armadaxp",
-                'mac': "AA:BB:CC:DD:EE:FF",
+                'mac': factory.make_mac_address().mac_address,
                 'menutitle': "menutitle",
                 'kernelimage': "/my/kernel",
                 'append': "append",
@@ -2275,6 +2279,42 @@
             }
         self.assertEqual(expected, observed)
 
+    def test_compose_enlistment_preseed_url_links_to_enlistment_preseed(self):
+        response = self.client.get(api.compose_enlistment_preseed_url())
+        self.assertEqual(
+            (httplib.OK, get_enlist_preseed()),
+            (response.status_code, response.content))
+
+    def test_compose_preseed_url_links_to_preseed_for_node(self):
+        node = factory.make_node()
+        response = self.client.get(api.compose_preseed_url(node))
+        self.assertEqual(
+            (httplib.OK, get_preseed(node)),
+            (response.status_code, response.content))
+
+    def test_compose_preseed_kernel_opt_returns_option_for_known_node(self):
+        mac = factory.make_mac_address()
+        self.assertEqual(
+            "auto url=%s" % api.compose_preseed_url(mac.node),
+            api.compose_preseed_kernel_opt(mac.mac_address))
+
+    def test_compose_preseed_kernel_opt_returns_option_for_unknown_node(self):
+        self.assertEqual(
+            "auto url=%s" % api.compose_enlistment_preseed_url(),
+            api.compose_preseed_kernel_opt(factory.getRandomMACAddress()))
+
+    def test_pxe_config_appends_enlistment_preseed_url_for_unknown_node(self):
+        params = self.get_params()
+        params['mac'] = factory.getRandomMACAddress()
+        response = self.client.get(reverse('pxeconfig'), params)
+        self.assertIn(api.compose_enlistment_preseed_url(), response.content)
+
+    def test_pxe_config_appends_preseed_url_for_known_node(self):
+        params = self.get_params()
+        node = MACAddress.objects.get(mac_address=params['mac']).node
+        response = self.client.get(reverse('pxeconfig'), params)
+        self.assertIn(api.compose_preseed_url(node), response.content)
+
 
 class TestNodeGroupsAPI(APITestCase):