launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #11267
[Merge] lp:~allenap/maas/pxe-intel-arch-config into lp:maas
Gavin Panella has proposed merging lp:~allenap/maas/pxe-intel-arch-config into lp:maas.
Requested reviews:
MAAS Maintainers (maas-maintainers)
For more details, see:
https://code.launchpad.net/~allenap/maas/pxe-intel-arch-config/+merge/121039
Create a KernelParameters object, and serialize it, in pxeconfig, eliminating the need for the transitional "kernel" module.
--
https://code.launchpad.net/~allenap/maas/pxe-intel-arch-config/+merge/121039
Your team MAAS Maintainers is requested to review the proposed merge of lp:~allenap/maas/pxe-intel-arch-config into lp:maas.
=== modified file 'src/maasserver/api.py'
--- src/maasserver/api.py 2012-08-23 10:10:42 +0000
+++ src/maasserver/api.py 2012-08-23 16:04:50 +0000
@@ -100,6 +100,7 @@
from formencode import validators
from formencode.validators import Invalid
from maasserver.enum import (
+ ARCHITECTURE,
NODE_PERMISSION,
NODE_STATUS,
)
@@ -115,7 +116,6 @@
get_node_create_form,
get_node_edit_form,
)
-from maasserver.kernel import compose_kernel_command_line
from maasserver.models import (
Config,
DHCPLease,
@@ -124,6 +124,11 @@
Node,
NodeGroup,
)
+from maasserver.preseed import (
+ compose_enlistment_preseed_url,
+ compose_preseed_url,
+ )
+from maasserver.server_address import get_maas_facing_server_address
from piston.doc import generate_doc
from piston.handler import (
AnonymousBaseHandler,
@@ -133,6 +138,7 @@
from piston.models import Token
from piston.resource import Resource
from piston.utils import rc
+from provisioningserver.kernel_opts import KernelParameters
dispatch_methods = {
@@ -1114,33 +1120,38 @@
def pxeconfig(request):
"""Get the PXE configuration given a node's details.
- :param mac: MAC address to produce a boot configuration for. This
- parameter is optional. If it is not given, the configuration
- will be the "default" one which boots into an enlistment image.
- :param arch: Main machine architecture.
- :param subarch: Sub-architecture, or "generic" if there is none.
+ Returns a JSON object corresponding to a
+ :class:`provisioningserver.kernel_opts.KernelParameters` instance.
+
+ :param mac: MAC address to produce a boot configuration for.
"""
- mac = request.GET.get('mac', None)
- arch = get_mandatory_param(request.GET, 'arch')
- subarch = request.GET.get('subarch', 'generic')
+ mac = get_mandatory_param(request.GET, 'mac')
# See if we have a record of this MAC address, and thus node.
try:
macaddress = MACAddress.objects.get(mac_address=mac)
except MACAddress.DoesNotExist:
macaddress = node = None
+ arch, subarch = ARCHITECTURE.i386, "generic"
+ preseed_url = compose_enlistment_preseed_url()
+ hostname = 'maas-enlist'
else:
node = macaddress.node
+ arch, subarch = node.architecture, "generic"
+ preseed_url = compose_preseed_url(node)
+ hostname = node.hostname
+ # XXX JeroenVermeulen 2012-08-06 bug=1013146: Stop hard-coding this.
+ release = 'precise'
purpose = get_boot_purpose(node)
- append = compose_kernel_command_line(node, arch, subarch, purpose=purpose)
-
- # XXX: allenap 2012-07-31 bug=1013146: 'precise' is hardcoded here.
- release = "precise"
-
- params = dict(
+ domain = 'local.lan' # TODO: This is probably not enough!
+ server_address = get_maas_facing_server_address()
+
+ params = KernelParameters(
arch=arch, subarch=subarch, release=release, purpose=purpose,
- append=append)
+ hostname=hostname, domain=domain, preseed_url=preseed_url,
+ log_host=server_address, fs_host=server_address)
return HttpResponse(
- json.dumps(params), content_type="application/json")
+ json.dumps(params._asdict()),
+ content_type="application/json")
=== removed file 'src/maasserver/kernel.py'
--- src/maasserver/kernel.py 2012-08-22 20:29:50 +0000
+++ src/maasserver/kernel.py 1970-01-01 00:00:00 +0000
@@ -1,63 +0,0 @@
-# Copyright 2012 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Generate kernel command-line for inclusion in PXE configs.
-
-This is a TRANSITIONAL module. This functionality will move to the pxeconfig()
-view in the most likely scenario.
-"""
-
-from __future__ import (
- absolute_import,
- print_function,
- unicode_literals,
- )
-
-__metaclass__ = type
-__all__ = [
- 'compose_kernel_command_line',
- ]
-
-from maasserver.preseed import (
- compose_enlistment_preseed_url,
- compose_preseed_url,
- )
-from maasserver.server_address import get_maas_facing_server_address
-from provisioningserver.kernel_opts import (
- compose_kernel_command_line_new,
- KernelParameters,
- )
-
-
-def compose_kernel_command_line(node, arch, subarch, purpose):
- """Generate a line of kernel options for booting `node`.
-
- Include these options in the PXE config file's APPEND argument.
-
- The node may be None, in which case it will boot into enlistment.
- """
- # XXX JeroenVermeulen 2012-08-06 bug=1013146: Stop hard-coding this.
- release = 'precise'
-
- # TODO: This is probably not enough!
- domain = 'local.lan'
-
- if node is None:
- preseed_url = compose_enlistment_preseed_url()
- else:
- preseed_url = compose_preseed_url(node)
-
- if node is None:
- # Not a known host; still needs enlisting. Make up a name.
- hostname = 'maas-enlist'
- else:
- hostname = node.hostname
-
- server_address = get_maas_facing_server_address()
-
- params = KernelParameters(
- arch=arch, subarch=subarch, release=release, purpose=purpose,
- hostname=hostname, domain=domain, preseed_url=preseed_url,
- log_host=server_address, fs_host=server_address)
-
- return compose_kernel_command_line_new(params)
=== modified file 'src/maasserver/tests/test_api.py'
--- src/maasserver/tests/test_api.py 2012-08-23 10:10:42 +0000
+++ src/maasserver/tests/test_api.py 2012-08-23 16:04:50 +0000
@@ -42,6 +42,7 @@
get_overrided_query_dict,
)
from maasserver.enum import (
+ ARCHITECTURE,
ARCHITECTURE_CHOICES,
NODE_AFTER_COMMISSIONING_ACTION,
NODE_STATUS,
@@ -93,6 +94,7 @@
POWER_TYPE,
POWER_TYPE_CHOICES,
)
+from provisioningserver.kernel_opts import KernelParameters
from provisioningserver.omshell import Omshell
from testresources import FixtureResource
from testtools.matchers import (
@@ -2244,14 +2246,10 @@
class TestPXEConfigAPI(AnonAPITestCase):
def get_params(self):
- return {
- 'arch': "armhf",
- 'subarch': "armadaxp",
- 'mac': factory.make_mac_address().mac_address,
- }
+ return {'mac': factory.make_mac_address().mac_address}
def get_optional_params(self):
- return ['subarch', 'mac']
+ return ['mac']
def get_pxeconfig(self, params=None):
"""Make a request to `pxeconfig`, and return its response dict."""
@@ -2278,37 +2276,15 @@
)),
response)
- def test_pxeconfig_returns_complete_config(self):
+ def test_pxeconfig_returns_all_kernel_parameters(self):
self.assertThat(
self.get_pxeconfig(),
- ContainsAll([
- 'arch',
- 'subarch',
- 'append',
- 'release',
- 'purpose',
- ]))
-
- def test_pxeconfig_copies_some_parameters_from_request(self):
- params_in = self.get_params()
- params_out = self.get_pxeconfig(params_in)
- copied_params = ['arch', 'subarch']
- self.assertEqual(
- {name: params_in[name] for name in copied_params},
- {name: params_out[name] for name in copied_params})
-
- def test_pxeconfig_adds_some_parameters(self):
- params_in = self.get_params()
- added_params = {'append', 'release', 'purpose'}
- for param in added_params:
- if param in params_in:
- del params_in[param]
- params_out = self.get_pxeconfig(params_in)
- self.assertEqual(
- set(params_out).difference(params_in), added_params)
- # The release is always "precise".
- self.assertEqual('precise', params_out['release'])
- self.assertThat(params_out['append'], Contains("auto url=http://"))
+ ContainsAll(KernelParameters._fields))
+
+ def test_pxeconfig_defaults_to_i386_when_node_unknown(self):
+ params_out = self.get_pxeconfig()
+ self.assertEqual(ARCHITECTURE.i386, params_out["arch"])
+ self.assertEqual("generic", params_out["subarch"])
def get_without_param(self, param):
"""Request a `pxeconfig()` response, but omit `param` from request."""
@@ -2323,39 +2299,29 @@
kernel_opts, 'get_ephemeral_name',
FakeMethod(result=factory.getRandomString()))
- def test_pxeconfig_handles_missing_parameters_appropriately(self):
- # Some parameters are optional, others are mandatory. The
- # absence of a mandatory parameter always results in a BAD
- # REQUEST response.
+ def test_pxeconfig_requires_mac_address(self):
+ # The `mac` parameter is mandatory.
self.silence_get_ephemeral_name()
- expected_response_to_missing_parameter = {
- 'arch': httplib.BAD_REQUEST,
- 'subarch': httplib.OK,
- 'mac': httplib.OK,
- }
- observed_response = {
- param: self.get_without_param(param).status_code
- for param in self.get_params()
- }
self.assertEqual(
- expected_response_to_missing_parameter, observed_response)
+ httplib.BAD_REQUEST,
+ self.get_without_param("mac").status_code)
- def test_pxeconfig_appends_enlistment_preseed_url_for_unknown_node(self):
+ def test_pxeconfig_has_enlistment_preseed_url_for_unknown_node(self):
self.silence_get_ephemeral_name()
params = self.get_params()
params['mac'] = factory.getRandomMACAddress()
response = self.client.get(reverse('pxeconfig'), params)
- self.assertIn(
+ self.assertEqual(
compose_enlistment_preseed_url(),
- json.loads(response.content)["append"])
+ json.loads(response.content)["preseed_url"])
- def test_pxeconfig_appends_preseed_url_for_known_node(self):
+ def test_pxeconfig_has_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(
+ self.assertEqual(
compose_preseed_url(node),
- json.loads(response.content)["append"])
+ json.loads(response.content)["preseed_url"])
def test_get_boot_purpose_unknown_node(self):
# A node that's not yet known to MAAS is assumed to be enlisting,
=== removed file 'src/maasserver/tests/test_kernel.py'
--- src/maasserver/tests/test_kernel.py 2012-08-22 20:53:31 +0000
+++ src/maasserver/tests/test_kernel.py 1970-01-01 00:00:00 +0000
@@ -1,176 +0,0 @@
-# Copyright 2012 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Test composition of kernel command lines."""
-
-from __future__ import (
- absolute_import,
- print_function,
- unicode_literals,
- )
-
-__metaclass__ = type
-__all__ = []
-
-import os
-
-from django.conf import settings
-from maasserver.api import get_boot_purpose
-from maasserver.kernel import compose_kernel_command_line
-from maasserver.preseed import (
- compose_enlistment_preseed_url,
- compose_preseed_url,
- )
-from maasserver.server_address import get_maas_facing_server_address
-from maasserver.testing.factory import factory
-from maasserver.testing.testcase import TestCase
-from maastesting.matchers import ContainsAll
-from provisioningserver.kernel_opts import (
- EphemeralImagesDirectoryNotFound,
- ISCSI_TARGET_NAME_PREFIX,
- )
-from provisioningserver.pxe.tftppath import compose_image_path
-from provisioningserver.testing.config import ConfigFixture
-
-
-class TestComposeKernelCommandLine(TestCase):
-
- def test_compose_kernel_command_line_accepts_None_for_unknown_node(self):
- self.assertIn(
- 'suite=precise',
- compose_kernel_command_line(
- None, factory.make_name('arch'), factory.make_name('subarch'),
- purpose=factory.make_name('purpose')))
-
- def test_compose_kernel_command_line_includes_preseed_url(self):
- node = factory.make_node()
- self.assertIn(
- "auto url=%s" % compose_preseed_url(node),
- compose_kernel_command_line(
- node, node.architecture, 'generic',
- purpose=factory.make_name('purpose')))
-
- def test_compose_kernel_command_line_includes_enlistment_preseed_url(self):
- self.assertIn(
- "auto url=%s" % compose_enlistment_preseed_url(),
- compose_kernel_command_line(
- None, factory.make_name("arch"), 'generic',
- purpose=factory.make_name('purpose')))
-
- def test_compose_kernel_command_line_includes_initrd(self):
- node = factory.make_node()
- initrd_path = compose_image_path(
- node.architecture, 'generic', 'precise',
- purpose=get_boot_purpose(node))
- self.assertIn(
- "initrd=%s" % initrd_path,
- compose_kernel_command_line(
- node, node.architecture, 'generic',
- purpose=get_boot_purpose(node)))
-
- def test_compose_kernel_command_line_includes_suite(self):
- # At the moment, the OS release we use is hard-coded to "precise."
- node = factory.make_node()
- suite = "precise"
- self.assertIn(
- "suite=%s" % suite,
- compose_kernel_command_line(
- node, node.architecture, 'generic',
- purpose=factory.make_name('purpose')))
-
- def test_compose_kernel_command_line_includes_hostname_and_domain(self):
- node = factory.make_node()
- # Cobbler seems to hard-code domain to "local.lan"; we may want
- # to change it, and update this test.
- domain = "local.lan"
- self.assertThat(
- compose_kernel_command_line(
- node, node.architecture, 'generic',
- purpose=factory.make_name('purpose')),
- ContainsAll([
- "hostname=%s" % node.hostname,
- "domain=%s" % domain,
- ]))
-
- def test_compose_kernel_command_line_makes_up_hostname_for_new_node(self):
- dummy_hostname = 'maas-enlist'
- self.assertIn(
- "hostname=%s" % dummy_hostname,
- compose_kernel_command_line(
- None, factory.make_name('arch'),
- factory.make_name('subarch'),
- purpose=factory.make_name('purpose')))
-
- def test_compose_kernel_command_line_includes_locale(self):
- node = factory.make_node()
- locale = "en_US"
- self.assertIn(
- "locale=%s" % locale,
- compose_kernel_command_line(
- node, node.architecture, 'generic',
- purpose=factory.make_name('purpose')))
-
- def test_compose_kernel_command_line_includes_log_settings(self):
- node = factory.make_node()
- log_host = factory.getRandomIPAddress()
- self.patch(settings, 'DEFAULT_MAAS_URL', 'http://%s/' % log_host)
- # Port 514 (UDP) is syslog.
- log_port = "514"
- text_priority = "critical"
- self.assertThat(
- compose_kernel_command_line(
- node, node.architecture, 'generic',
- purpose=factory.make_name('purpose')),
- ContainsAll([
- "log_host=%s" % log_host,
- "log_port=%s" % log_port,
- "text priority=%s" % text_priority,
- ]))
-
- def create_ephemeral_info(self, name, arch, release):
- """Create a pseudo-real ephemeral info file."""
- epheneral_info = """
- release=%s
- stream=ephemeral
- label=release
- serial=20120424
- arch=%s
- name=%s
- """ % (release, arch, name)
- ephemeral_root = self.make_dir()
- config = {"boot": {"ephemeral": {"directory": ephemeral_root}}}
- self.useFixture(ConfigFixture(config))
- ephemeral_dir = os.path.join(
- ephemeral_root, release, 'ephemeral', arch, release)
- os.makedirs(ephemeral_dir)
- factory.make_file(
- ephemeral_dir, name='info', contents=epheneral_info)
-
- def test_compose_kernel_command_line_inc_purpose_opts_comm_node(self):
- # The result of compose_kernel_command_line includes the purpose
- # options for a "commissioning" node.
- ephemeral_name = factory.make_name("ephemeral")
- arch = factory.make_name('arch')
- self.create_ephemeral_info(ephemeral_name, arch, "precise")
- node = factory.make_node()
- self.assertThat(
- compose_kernel_command_line(
- node, arch,
- factory.make_name('subarch'),
- purpose="commissioning"),
- ContainsAll([
- "iscsi_target_name=%s:%s" % (
- ISCSI_TARGET_NAME_PREFIX, ephemeral_name),
- "iscsi_target_port=3260",
- "iscsi_target_ip=%s" % get_maas_facing_server_address(),
- ]))
-
- def test_compose_kernel_command_line_reports_error_about_missing_dir(self):
- missing_dir = factory.make_name('missing-dir')
- config = {"boot": {"ephemeral": {"directory": missing_dir}}}
- self.useFixture(ConfigFixture(config))
- node = factory.make_node()
- self.assertRaises(
- EphemeralImagesDirectoryNotFound,
- compose_kernel_command_line, node, factory.make_name('arch'),
- factory.make_name('subarch'), purpose="commissioning")