← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~jtv/maas/bug-1042877 into lp:maas

 

Jeroen T. Vermeulen has proposed merging lp:~jtv/maas/bug-1042877 into lp:maas.

Requested reviews:
  MAAS Maintainers (maas-maintainers)

For more details, see:
https://code.launchpad.net/~jtv/maas/bug-1042877/+merge/122049

I pre-imped this with Gavin, but also called in Daviey and Robie for details.  A lot changes, and unfortunately it all more or less had to do so in one go:

 * Instead of re-using /var/lib/tftpboot/, create our own /var/lib/maas/tftp/.

 * No more "maas/" prefix: pxelinux.0, pxelinux.cfg/01-aa-bb-cc-dd-ee-ff, i386/generic/precise/install/kernel.

 * Don't download pxelinux.0; take just the i386 binary from syslinux.

 * Consistently get all pxelinux files from /usr/lib/syslinux; don't mix installed modules with downloaded loaders.

 * Drop bootpath and related complexity.

One small bit that I managed to leave for later: CURRENT_RELEASE should no longer be needed in maas-import-pxe-files.  I'll remove that separately.

Rather than trawl through the MP diff, you may find it easier to read the commit log as a blow-by-blow account.


Jeroen
-- 
https://code.launchpad.net/~jtv/maas/bug-1042877/+merge/122049
Your team MAAS Maintainers is requested to review the proposed merge of lp:~jtv/maas/bug-1042877 into lp:maas.
=== modified file 'etc/pserv.yaml'
--- etc/pserv.yaml	2012-08-30 06:25:25 +0000
+++ etc/pserv.yaml	2012-08-30 12:19:20 +0000
@@ -31,7 +31,7 @@
 ## TFTP configuration.
 #
 tftp:
-  # root: /var/lib/tftpboot
+  root: /var/lib/maas/tftp
   # port: 69
   port: 5244
   ## The URL to be contacted to generate PXE configurations.

=== modified file 'scripts/maas-import-pxe-files'
--- scripts/maas-import-pxe-files	2012-08-28 23:35:55 +0000
+++ scripts/maas-import-pxe-files	2012-08-30 12:19:20 +0000
@@ -6,7 +6,7 @@
 # pre-boot loader, kernels, and initrd images.
 #
 # This script downloads the required files into the TFTP home directory
-# (by default, /var/lib/tftpboot).  Run it with the necessarily privileges
+# (by default, /var/lib/maas/tftp).  Run it with the necessarily privileges
 # to write them there.
 
 # Exit immediately if a command exits with a non-zero status.
@@ -64,31 +64,15 @@
 }
 
 
-# Download the pre-boot loader, pxelinux.0, for architecture $1.  If
-# successful, install it for netboot use.  (Not all architectures need this
-# file, and there's rarely an urgent need for the very latest file, so if
-# the download fails this function just skips it.)
+# Copy the pre-boot loader pxelinux.0, and modules we need, from the
+# installed syslinux version.  Install it into the TFTP tree for
+# netbooting.
 update_pre_boot_loader() {
-    local arch=$1
-    local url=$(compose_installer_download_url $arch $CURRENT_RELEASE)
-    if ! $DOWNLOAD $url/pxelinux.0
-    then
-        echo "Could not download pre-boot loader for $arch; skipping."
-        return
-    fi
-
-    # If the file has changed, move it into place (replacing any previous
-    # version).  Otherwise, leave the filesystem alone.
-    if [ -f pxelinux.0 ]
-    then
-        # TODO: pxelinux.0 is downloaded but there's no reason why it can't
-        # come from the syslinux package like chain.c32 is.
-        maas-provision install-pxe-bootloader --loader='pxelinux.0'
-        maas-provision install-pxe-bootloader \
-            --loader='/usr/lib/syslinux/chain.c32'
-        maas-provision install-pxe-bootloader \
-            --loader='/usr/lib/syslinux/ifcpu64.c32'
-    fi
+    for loader_file in pxelinux.0 chain.c32 ifcpu64.c32
+    do
+        maas-provision install-pxe-bootloader \
+            --loader="/usr/lib/syslinux/$loader_file"
+    done
 }
 
 
@@ -122,14 +106,8 @@
     echo "Downloading to temporary location $DOWNLOAD_DIR."
     pushd -- $DOWNLOAD_DIR
 
-    # All files we create here are public.  The TFTP user will need to be
-    # able to read them.
-    umask a+r
-
     for arch in $ARCHES
     do
-        update_pre_boot_loader $arch
-
         for release in $RELEASES
         do
             update_install_files $arch $release
@@ -151,7 +129,11 @@
 
 
 main() {
+    # All files we create here are public.  The TFTP user will need to be
+    # able to read them.
+    umask a+r
 
+    update_pre_boot_loader
     import_install_images
     import_ephemeral_images
 }

=== modified file 'src/provisioningserver/config.py'
--- src/provisioningserver/config.py	2012-08-30 06:25:25 +0000
+++ src/provisioningserver/config.py	2012-08-30 12:19:20 +0000
@@ -59,7 +59,7 @@
 
     if_key_missing = None
 
-    root = String(if_missing="/var/lib/tftpboot")
+    root = String(if_missing="/var/lib/maas/tftp")
     port = Int(min=1, max=65535, if_missing=69)
     generator = String(if_missing=b"http://localhost/MAAS/api/1.0/pxeconfig/";)
 

=== modified file 'src/provisioningserver/pxe/config.commissioning.template'
--- src/provisioningserver/pxe/config.commissioning.template	2012-08-24 12:48:12 +0000
+++ src/provisioningserver/pxe/config.commissioning.template	2012-08-30 12:19:20 +0000
@@ -6,14 +6,14 @@
 
 LABEL amd64
   SAY Booting (amd64) under MAAS direction...
-  KERNEL {{kernel_params(arch="amd64") | kernel_path | relative}}
-  INITRD {{kernel_params(arch="amd64") | initrd_path | relative}}
+  KERNEL {{kernel_params(arch="amd64") | kernel_path }}
+  INITRD {{kernel_params(arch="amd64") | initrd_path }}
   APPEND {{kernel_params(arch="amd64") | kernel_command}}
   IPAPPEND 2
 
 LABEL i386
   SAY Booting (i386) under MAAS direction...
-  KERNEL {{kernel_params(arch="i386") | kernel_path | relative}}
-  INITRD {{kernel_params(arch="i386") | initrd_path | relative}}
+  KERNEL {{kernel_params(arch="i386") | kernel_path }}
+  INITRD {{kernel_params(arch="i386") | initrd_path }}
   APPEND {{kernel_params(arch="i386") | kernel_command}}
   IPAPPEND 2

=== modified file 'src/provisioningserver/pxe/config.py'
--- src/provisioningserver/pxe/config.py	2012-08-24 19:14:58 +0000
+++ src/provisioningserver/pxe/config.py	2012-08-30 12:19:20 +0000
@@ -23,7 +23,6 @@
 from errno import ENOENT
 from os import path
 
-import posixpath
 from provisioningserver.kernel_opts import compose_kernel_command_line_new
 from provisioningserver.pxe.tftppath import compose_image_path
 import tempita
@@ -71,18 +70,14 @@
             "No PXE template found in %r!" % template_dir)
 
 
-def render_pxe_config(bootpath, kernel_params, **extra):
+def render_pxe_config(kernel_params, **extra):
     """Render a PXE configuration file as a unicode string.
 
-    :param bootpath: The directory path of `pxelinux.0`.
     :param kernel_params: An instance of `KernelParameters`.
     :param extra: Allow for other arguments. This is a safety valve;
         parameters generated in another component (for example, see
         `TFTPBackend.get_config_reader`) won't cause this to break.
     """
-    if bootpath is None:
-        bootpath = ''
-
     template = get_pxe_template(
         kernel_params.purpose, kernel_params.arch,
         kernel_params.subarch)
@@ -95,24 +90,19 @@
             params.arch, params.subarch,
             params.release, params.purpose)
 
-    def initrd(params):
+    def initrd_path(params):
         return "%s/initrd.gz" % image_dir(params)
 
-    def kernel(params):
+    def kernel_path(params):
         return "%s/linux" % image_dir(params)
 
     def kernel_command(params):
         return compose_kernel_command_line_new(params)
 
-    def relative(path):
-        # Return `path` relative to `bootpath`.
-        return posixpath.relpath(path, start=bootpath)
-
     namespace = {
-        "initrd_path": initrd,
+        "initrd_path": initrd_path,
         "kernel_command": kernel_command,
         "kernel_params": kernel_params,
-        "kernel_path": kernel,
-        "relative": relative,
+        "kernel_path": kernel_path,
         }
     return template.substitute(namespace)

=== modified file 'src/provisioningserver/pxe/config.template'
--- src/provisioningserver/pxe/config.template	2012-08-24 12:48:12 +0000
+++ src/provisioningserver/pxe/config.template	2012-08-30 12:19:20 +0000
@@ -2,7 +2,7 @@
 
 LABEL execute
   SAY Booting under MAAS direction...
-  KERNEL {{kernel_params | kernel_path | relative}}
-  INITRD {{kernel_params | initrd_path | relative}}
+  KERNEL {{kernel_params | kernel_path }}
+  INITRD {{kernel_params | initrd_path }}
   APPEND {{kernel_params | kernel_command}}
   IPAPPEND 2

=== modified file 'src/provisioningserver/pxe/install_bootloader.py'
--- src/provisioningserver/pxe/install_bootloader.py	2012-08-17 14:28:27 +0000
+++ src/provisioningserver/pxe/install_bootloader.py	2012-08-30 12:19:20 +0000
@@ -30,7 +30,7 @@
     """Locate a loader's destination, creating the directory if needed.
 
     :param tftproot: The root directory served up by the TFTP server,
-        e.g. /var/lib/tftpboot/.
+        e.g. /var/lib/maas/tftp/.
     :return: Full path describing the directory that the installed loader
         should end up having.
     """

=== modified file 'src/provisioningserver/pxe/install_image.py'
--- src/provisioningserver/pxe/install_image.py	2012-07-23 10:24:39 +0000
+++ src/provisioningserver/pxe/install_image.py	2012-08-30 12:19:20 +0000
@@ -33,7 +33,7 @@
     """Locate an image's destination.  Create containing directory if needed.
 
     :param tftproot: The root directory served up by the TFTP server,
-        e.g. /var/lib/tftpboot/.
+        e.g. /var/lib/maas/tftp/.
     :param arch: Main architecture to locate the destination for.
     :param subarch: Sub-architecture of the main architecture.
     :param release: OS release name, e.g. "precise".

=== modified file 'src/provisioningserver/pxe/tests/test_config.py'
--- src/provisioningserver/pxe/tests/test_config.py	2012-08-24 16:23:15 +0000
+++ src/provisioningserver/pxe/tests/test_config.py	2012-08-30 12:19:20 +0000
@@ -21,7 +21,6 @@
 from maastesting.matchers import ContainsAll
 from maastesting.testcase import TestCase
 import mock
-import posixpath
 from provisioningserver import kernel_opts
 from provisioningserver.pxe import config
 from provisioningserver.pxe.config import render_pxe_config
@@ -150,9 +149,8 @@
     def test_render(self):
         # Given the right configuration options, the PXE configuration is
         # correctly rendered.
-        bootpath = factory.make_name("bootpath")
         params = make_kernel_parameters()
-        output = render_pxe_config(bootpath=bootpath, kernel_params=params)
+        output = render_pxe_config(kernel_params=params)
         # The output is always a Unicode string.
         self.assertThat(output, IsInstance(unicode))
         # The template has rendered without error. PXELINUX configurations
@@ -162,7 +160,6 @@
         image_dir = compose_image_path(
             arch=params.arch, subarch=params.subarch,
             release=params.release, purpose=params.purpose)
-        image_dir = posixpath.relpath(image_dir, bootpath)
         self.assertThat(
             output, MatchesAll(
                 MatchesRegex(
@@ -177,10 +174,7 @@
 
     def test_render_with_extra_arguments_does_not_affect_output(self):
         # render_pxe_config() allows any keyword arguments as a safety valve.
-        options = {
-            "bootpath": factory.make_name("bootpath"),
-            "kernel_params": make_kernel_parameters(),
-            }
+        options = {"kernel_params": make_kernel_parameters()}
         # Capture the output before sprinking in some random options.
         output_before = render_pxe_config(**options)
         # Sprinkle some magic in.
@@ -196,7 +190,6 @@
         # If purpose is "local", the config.localboot.template should be
         # used.
         options = {
-            "bootpath": factory.make_name("bootpath"),
             "kernel_params":
                 make_kernel_parameters()._replace(purpose="local"),
             }
@@ -207,7 +200,6 @@
         # Intel i386 is a special case and needs to use the chain.c32
         # loader as the LOCALBOOT PXE directive is unreliable.
         options = {
-            "bootpath": factory.make_name("bootpath"),
             "kernel_params": make_kernel_parameters()._replace(
                 arch="i386", purpose="local"),
             }
@@ -219,7 +211,6 @@
         # Intel amd64 is a special case and needs to use the chain.c32
         # loader as the LOCALBOOT PXE directive is unreliable.
         options = {
-            "bootpath": factory.make_name("bootpath"),
             "kernel_params": make_kernel_parameters()._replace(
                 arch="amd64", purpose="local"),
             }
@@ -233,7 +224,6 @@
         get_ephemeral_name = self.patch(kernel_opts, "get_ephemeral_name")
         get_ephemeral_name.return_value = factory.make_name("ephemeral")
         options = {
-            "bootpath": factory.make_name("bootpath"),
             "kernel_params": make_kernel_parameters()._replace(
                 purpose="commissioning"),
             }
@@ -251,13 +241,14 @@
             default_section["APPEND"].split())
         # Both "i386" and "amd64" sections exist.
         self.assertThat(config, ContainsAll(("i386", "amd64")))
-        # Each section defines KERNEL, INITRD, and APPEND settings, each
-        # containing paths referring to their architectures.
+        # Each section defines KERNEL, INITRD, and APPEND settings.  The
+        # KERNEL and INITRD ones contain paths referring to their
+        # architectures.
         for section_label in ("i386", "amd64"):
             section = config[section_label]
             self.assertThat(
                 section, ContainsAll(("KERNEL", "INITRD", "APPEND")))
-            contains_arch_path = Contains("/%s/" % section_label)
+            contains_arch_path = StartsWith("%s/" % section_label)
             self.assertThat(section["KERNEL"], contains_arch_path)
             self.assertThat(section["INITRD"], contains_arch_path)
-            self.assertThat(section["APPEND"], contains_arch_path)
+            self.assertIn("APPEND", section)

=== modified file 'src/provisioningserver/pxe/tests/test_install_image.py'
--- src/provisioningserver/pxe/tests/test_install_image.py	2012-07-23 13:25:15 +0000
+++ src/provisioningserver/pxe/tests/test_install_image.py	2012-08-30 12:19:20 +0000
@@ -79,13 +79,13 @@
     def test_make_destination_follows_pxe_path_conventions(self):
         # The directory that make_destination returns follows the PXE
         # directory hierarchy specified for MAAS:
-        # /var/lib/tftproot/maas/<arch>/<subarch>/<release>/<purpose>
-        # (Where the /var/lib/tftproot/ part is configurable, so we
+        # /var/lib/maas/tftp/<arch>/<subarch>/<release>/<purpose>
+        # (Where the /var/lib/maas/tftp/ part is configurable, so we
         # can test this without overwriting system files).
         tftproot = self.make_dir()
         arch, subarch, release, purpose = make_arch_subarch_release_purpose()
         self.assertEqual(
-            os.path.join(tftproot, 'maas', arch, subarch, release, purpose),
+            os.path.join(tftproot, arch, subarch, release, purpose),
             make_destination(tftproot, arch, subarch, release, purpose))
 
     def test_make_destination_creates_directory_if_not_present(self):

=== modified file 'src/provisioningserver/pxe/tests/test_tftppath.py'
--- src/provisioningserver/pxe/tests/test_tftppath.py	2012-08-17 14:11:20 +0000
+++ src/provisioningserver/pxe/tests/test_tftppath.py	2012-08-30 12:19:20 +0000
@@ -41,7 +41,7 @@
     def test_compose_config_path_follows_maas_pxe_directory_layout(self):
         name = factory.make_name('config')
         self.assertEqual(
-            'maas/pxelinux.cfg/%02x-%s' % (ARP_HTYPE.ETHERNET, name),
+            'pxelinux.cfg/%02x-%s' % (ARP_HTYPE.ETHERNET, name),
             compose_config_path(name))
 
     def test_compose_config_path_does_not_include_tftp_root(self):
@@ -56,7 +56,7 @@
         release = factory.make_name('release')
         purpose = factory.make_name('purpose')
         self.assertEqual(
-            'maas/%s/%s/%s/%s' % (arch, subarch, release, purpose),
+            '%s/%s/%s/%s' % (arch, subarch, release, purpose),
             compose_image_path(arch, subarch, release, purpose))
 
     def test_compose_image_path_does_not_include_tftp_root(self):
@@ -69,7 +69,7 @@
             Not(StartsWith(self.tftproot)))
 
     def test_compose_bootloader_path_follows_maas_pxe_directory_layout(self):
-        self.assertEqual('maas/pxelinux.0', compose_bootloader_path())
+        self.assertEqual('pxelinux.0', compose_bootloader_path())
 
     def test_compose_bootloader_path_does_not_include_tftp_root(self):
         self.assertThat(

=== modified file 'src/provisioningserver/pxe/tftppath.py'
--- src/provisioningserver/pxe/tftppath.py	2012-08-30 06:25:25 +0000
+++ src/provisioningserver/pxe/tftppath.py	2012-08-30 12:19:20 +0000
@@ -29,7 +29,7 @@
     simulate PXELINUX and don't actually load `pxelinux.0`, but use its path
     to figure out where configuration files are located.
     """
-    return "maas/pxelinux.0"
+    return "pxelinux.0"
 
 
 # TODO: move this; it is now only used for testing.
@@ -48,7 +48,7 @@
     # Not using os.path.join: this is a TFTP path, not a native path. Yes, in
     # practice for us they're the same. We always assume that the ARP HTYPE
     # (hardware type) that PXELINUX sends is Ethernet.
-    return "maas/pxelinux.cfg/{htype:02x}-{mac}".format(
+    return "pxelinux.cfg/{htype:02x}-{mac}".format(
         htype=ARP_HTYPE.ETHERNET, mac=mac)
 
 
@@ -66,7 +66,7 @@
     :return: Path for the corresponding image directory (containing a
         kernel and initrd) as exposed over TFTP.
     """
-    return '/'.join(['maas', arch, subarch, release, purpose])
+    return '/'.join([arch, subarch, release, purpose])
 
 
 def locate_tftp_path(path, tftproot):

=== modified file 'src/provisioningserver/tests/test_config.py'
--- src/provisioningserver/tests/test_config.py	2012-08-24 10:53:26 +0000
+++ src/provisioningserver/tests/test_config.py	2012-08-30 12:19:20 +0000
@@ -147,7 +147,7 @@
         'tftp': {
             'generator': 'http://localhost/MAAS/api/1.0/pxeconfig/',
             'port': 69,
-            'root': "/var/lib/tftpboot",
+            'root': "/var/lib/maas/tftp",
             },
         }
 

=== modified file 'src/provisioningserver/tests/test_maas_import_pxe_files.py'
--- src/provisioningserver/tests/test_maas_import_pxe_files.py	2012-08-17 14:45:13 +0000
+++ src/provisioningserver/tests/test_maas_import_pxe_files.py	2012-08-30 12:19:20 +0000
@@ -23,11 +23,7 @@
     )
 from provisioningserver.pxe import tftppath
 from provisioningserver.testing.config import ConfigFixture
-from testtools.matchers import (
-    FileContains,
-    FileExists,
-    Not,
-    )
+from testtools.matchers import FileContains
 
 
 def read_file(path, name):
@@ -97,7 +93,7 @@
         archive = self.make_dir()
         download = compose_download_dir(archive, arch, release)
         os.makedirs(download)
-        for filename in ['initrd.gz', 'linux', 'pxelinux.0']:
+        for filename in ['initrd.gz', 'linux']:
             factory.make_file(download, filename)
         return archive
 
@@ -135,40 +131,27 @@
         with open(os.devnull, 'wb') as dev_null:
             check_call(script, env=env, stdout=dev_null)
 
-    def test_downloads_pre_boot_loader(self):
+    def test_procures_pre_boot_loader(self):
         arch = factory.make_name('arch')
         release = 'precise'
         archive = self.make_downloads(arch=arch, release=release)
         self.call_script(archive, self.tftproot, arch=arch, release=release)
         tftp_path = compose_tftp_bootloader_path(self.tftproot)
-        download_path = compose_download_dir(archive, arch, release)
-        expected_contents = read_file(download_path, 'pxelinux.0')
+        expected_contents = read_file('/usr/lib/syslinux', 'pxelinux.0')
         self.assertThat(tftp_path, FileContains(expected_contents))
 
-    def test_ignores_missing_pre_boot_loader(self):
-        arch = factory.make_name('arch')
-        release = 'precise'
-        archive = self.make_downloads(arch=arch, release=release)
-        download_path = compose_download_dir(archive, arch, release)
-        os.remove(os.path.join(download_path, 'pxelinux.0'))
-        self.call_script(archive, self.tftproot, arch=arch, release=release)
-        tftp_path = compose_tftp_bootloader_path(self.tftproot)
-        self.assertThat(tftp_path, Not(FileExists()))
-
     def test_updates_pre_boot_loader(self):
         arch = factory.make_name('arch')
         release = 'precise'
         tftp_path = compose_tftp_bootloader_path(self.tftproot)
-        os.makedirs(os.path.dirname(tftp_path))
         with open(tftp_path, 'w') as existing_file:
             existing_file.write(factory.getRandomString())
         archive = self.make_downloads(arch=arch, release=release)
         self.call_script(archive, self.tftproot, arch=arch, release=release)
-        download_path = compose_download_dir(archive, arch, release)
-        expected_contents = read_file(download_path, 'pxelinux.0')
+        expected_contents = read_file('/usr/lib/syslinux', 'pxelinux.0')
         self.assertThat(tftp_path, FileContains(expected_contents))
 
-    def test_downloads_install_image(self):
+    def test_procures_install_image(self):
         arch = factory.make_name('arch')
         release = 'precise'
         archive = self.make_downloads(arch=arch, release=release)

=== modified file 'src/provisioningserver/tests/test_tftp.py'
--- src/provisioningserver/tests/test_tftp.py	2012-08-27 12:00:44 +0000
+++ src/provisioningserver/tests/test_tftp.py	2012-08-30 12:19:20 +0000
@@ -70,10 +70,7 @@
         The path is intended to match `re_config_file`, and the components are
         the expected groups from a match.
         """
-        components = {
-            "bootpath": b"maas",  # Static.
-            "mac": factory.getRandomMACAddress(b"-"),
-            }
+        components = {"mac": factory.getRandomMACAddress(b"-")}
         config_path = compose_config_path(components["mac"])
         return config_path, components
 
@@ -115,17 +112,17 @@
         mac = 'aa-bb-cc-dd-ee-ff'
         match = TFTPBackend.re_config_file.match('pxelinux.cfg/01-%s' % mac)
         self.assertIsNotNone(match)
-        self.assertEqual({'mac': mac, 'bootpath': None}, match.groupdict())
+        self.assertEqual({'mac': mac}, match.groupdict())
 
     def test_re_config_file_matches_pxelinux_cfg_with_leading_slash(self):
         mac = 'aa-bb-cc-dd-ee-ff'
         match = TFTPBackend.re_config_file.match('/pxelinux.cfg/01-%s' % mac)
         self.assertIsNotNone(match)
-        self.assertEqual({'mac': mac, 'bootpath': None}, match.groupdict())
+        self.assertEqual({'mac': mac}, match.groupdict())
 
     def test_re_config_file_does_not_match_non_config_file(self):
         self.assertIsNone(
-            TFTPBackend.re_config_file.match('maas/pxelinux.cfg/kernel'))
+            TFTPBackend.re_config_file.match('pxelinux.cfg/kernel'))
 
     def test_re_config_file_does_not_match_file_in_root(self):
         self.assertIsNone(
@@ -153,18 +150,16 @@
     def test_get_generator_url(self):
         # get_generator_url() merges the parameters obtained from the request
         # file path (arch, subarch, name) into the configured generator URL.
-        bootpath = factory.make_name("bootpath")
         mac = factory.getRandomMACAddress(b"-")
         dummy = factory.make_name("dummy").encode("ascii")
         backend_url = b"http://example.com/?"; + urlencode({b"dummy": dummy})
         backend = TFTPBackend(self.make_dir(), backend_url)
         # params is an example of the parameters obtained from a request.
-        params = {"bootpath": bootpath, "mac": mac}
+        params = {"mac": mac}
         generator_url = urlparse(backend.get_generator_url(params))
         self.assertEqual("example.com", generator_url.hostname)
         query = parse_qsl(generator_url.query)
         query_expected = [
-            ("bootpath", bootpath),
             ("dummy", dummy),
             ("mac", mac),
             ]
@@ -200,9 +195,7 @@
 
         reader = yield backend.get_reader(config_path)
         output = reader.read(10000)
-        # The expected parameters include bootpath; this is extracted from the
-        # file path by re_config_file.
-        expected_params = dict(mac=mac, bootpath="maas")
+        expected_params = dict(mac=mac)
         observed_params = json.loads(output)
         self.assertEqual(expected_params, observed_params)
 
@@ -212,10 +205,7 @@
         # `IReader` of a PXE configuration, rendered by `render_pxe_config`.
         backend = TFTPBackend(self.make_dir(), b"http://example.com/";)
         # Fake configuration parameters, as discovered from the file path.
-        fake_params = {
-            "bootpath": "maas",
-            "mac": factory.getRandomMACAddress(b"-"),
-            }
+        fake_params = {"mac": factory.getRandomMACAddress(b"-")}
         # Fake kernel configuration parameters, as returned from the API call.
         fake_kernel_params = make_kernel_parameters()
 

=== modified file 'src/provisioningserver/tftp.py'
--- src/provisioningserver/tftp.py	2012-08-24 18:34:57 +0000
+++ src/provisioningserver/tftp.py	2012-08-30 12:19:20 +0000
@@ -86,14 +86,7 @@
     re_config_file = re.compile(
         r'''
         # Optional leading slash(es).
-        ^/?
-        # Optional boot path prefix (separated from the rest by slash):
-        (?:
-            (?P<bootpath>
-                maas
-            )
-            /
-        )?
+        ^/*
         pxelinux[.]cfg    # PXELINUX expects this.
         /
         {htype:02x}    # ARP HTYPE.