launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #10867
[Merge] lp:~julian-edwards/maas/chain-booting into lp:maas
Julian Edwards has proposed merging lp:~julian-edwards/maas/chain-booting into lp:maas.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1034198 in MAAS: "Local booting a node uses PXE's unreliable LOCALBOOT"
https://bugs.launchpad.net/maas/+bug/1034198
For more details, see:
https://code.launchpad.net/~julian-edwards/maas/chain-booting/+merge/119314
(Somewhat pre-imped with jtv.)
After previously adding the PXE template to do local booting, I found out that the LOCALBOOT directive is apparently unreliable on Intel hardware.
This branch uses the chain.32 loader to do local boot on Intel instead. There's a few changes to support this:
* maas-import-pxe-files uses the install_bootloader stuff to install the chain.32 file in the right place
* chain.32 comes from the local file system and is installed by the syslinux package so this is now mentioned in the required packages. [As a side note, we could also start getting pxelinux.0 from there instead of downloading it]
* The install_bootloader stuff was a bit broken in that it always copied everything to a single file called pxelinux.0 - this is because compose_bootloader_path returns the file name not just its path! However, since the way PXE works all links off the location of the pxelinux.0 file I chose not to amend that function and instead operate in the way that PXE does and hack the filename off the end and use its base directory as a destination to copy whatever file is given by args.loader.
* There's a new template that uses chain.c32 and a fix to render_pxe_config to make use of it.
* Finally, the existing localboot template was using an arg of -1 to LOCALBOOT. This forces an error condition in the loader and makes the BIOS head to its next configured boot device - we want to *force* a local boot instead, so -1 is now 0 which does that.
--
https://code.launchpad.net/~julian-edwards/maas/chain-booting/+merge/119314
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~julian-edwards/maas/chain-booting into lp:maas.
=== modified file 'required-packages/base'
--- required-packages/base 2012-08-01 05:55:00 +0000
+++ required-packages/base 2012-08-13 08:56:21 +0000
@@ -30,4 +30,5 @@
python-txamqp
python-yaml
rabbitmq-server
+syslinux
tgt
=== modified file 'scripts/maas-import-pxe-files'
--- scripts/maas-import-pxe-files 2012-08-03 15:12:09 +0000
+++ scripts/maas-import-pxe-files 2012-08-13 08:56:21 +0000
@@ -75,6 +75,8 @@
# TODO: Pass sub-architecture once we support those.
maas-provision install-pxe-bootloader \
--arch=$arch --loader='pxelinux.0'
+ maas-provision install-pxe-bootloader \
+ --arch=$arch --loader='/usr/lib/syslinux/chain.c32'
fi
}
=== added file 'src/provisioningserver/pxe/config.localboot-intel.template'
--- src/provisioningserver/pxe/config.localboot-intel.template 1970-01-01 00:00:00 +0000
+++ src/provisioningserver/pxe/config.localboot-intel.template 2012-08-13 08:56:21 +0000
@@ -0,0 +1,9 @@
+DEFAULT local
+PROMPT 0
+TIMEOUT 0
+TOTALTIMEOUT 0
+ONTIMEOUT local
+
+LABEL local
+ KERNEL chain.c32
+
=== modified file 'src/provisioningserver/pxe/config.localboot.template'
--- src/provisioningserver/pxe/config.localboot.template 2012-08-07 06:39:44 +0000
+++ src/provisioningserver/pxe/config.localboot.template 2012-08-13 08:56:21 +0000
@@ -5,5 +5,4 @@
LABEL execute
SAY Booting local disk ...
- LOCALBOOT -1
-
+ LOCALBOOT 0
=== modified file 'src/provisioningserver/pxe/config.py'
--- src/provisioningserver/pxe/config.py 2012-08-07 06:39:44 +0000
+++ src/provisioningserver/pxe/config.py 2012-08-13 08:56:21 +0000
@@ -32,6 +32,8 @@
template_filename = path.join(template_dir, "config.template")
template_localboot_filename = path.join(
template_dir, "config.localboot.template")
+template_localboot_intel_filename = path.join(
+ template_dir, "config.localboot-intel.template")
def render_pxe_config(
@@ -48,9 +50,15 @@
parameters generated in another component (for example, see
`TFTPBackend.get_config_reader`) won't cause this to break.
"""
+ # Templates are loaded each time here so that they can be changed on
+ # the fly without restarting the provisioning server.
if purpose == "local":
- template = tempita.Template.from_filename(
- template_localboot_filename, encoding="UTF-8")
+ if arch in ("i386", "amd64"):
+ template = tempita.Template.from_filename(
+ template_localboot_intel_filename, encoding="UTF-8")
+ else:
+ template = tempita.Template.from_filename(
+ template_localboot_filename, encoding="UTF-8")
# No params in local boot pxeconfig, but using a template anyway
# in case we decide to do so in the future.
return template.substitute()
=== modified file 'src/provisioningserver/pxe/install_bootloader.py'
--- src/provisioningserver/pxe/install_bootloader.py 2012-07-23 10:24:39 +0000
+++ src/provisioningserver/pxe/install_bootloader.py 2012-08-13 08:56:21 +0000
@@ -44,7 +44,7 @@
directory = os.path.dirname(path)
if not os.path.isdir(directory):
os.makedirs(directory)
- return path
+ return directory
def are_identical_files(old, new):
@@ -103,11 +103,9 @@
"""Install a PXE pre-boot loader into the TFTP directory structure.
This won't overwrite an existing loader if its contents are unchanged.
- However the new loader you give it will be deleted regardless.
"""
config = Config.load(args.config_file)
tftproot = config["tftp"]["root"]
- destination = make_destination(tftproot, args.arch, args.subarch)
+ destination_path = make_destination(tftproot, args.arch, args.subarch)
+ destination = os.path.join(destination_path, os.path.basename(args.loader))
install_bootloader(args.loader, destination)
- if os.path.exists(args.loader):
- os.remove(args.loader)
=== modified file 'src/provisioningserver/pxe/tests/test_config.py'
--- src/provisioningserver/pxe/tests/test_config.py 2012-08-07 06:39:35 +0000
+++ src/provisioningserver/pxe/tests/test_config.py 2012-08-13 08:56:21 +0000
@@ -97,4 +97,34 @@
"append": factory.make_name("append"),
}
output = render_pxe_config(**options)
- self.assertIn("LOCALBOOT -1", output)
+ self.assertIn("LOCALBOOT 0", output)
+
+ def test_render_pxe_config_with_local_purpose_i386_arch(self):
+ # Intel i386 is a special case and needs to use the chain.c32
+ # loader as the LOCALBOOT PXE directive is unreliable.
+ options = {
+ "arch": "i386",
+ "subarch": factory.make_name("subarch"),
+ "release": factory.make_name("release"),
+ "purpose": "local",
+ "bootpath": factory.make_name("bootpath"),
+ "append": factory.make_name("append"),
+ }
+ output = render_pxe_config(**options)
+ self.assertIn("chain.c32", output)
+ self.assertNotIn("LOCALBOOT", output)
+
+ def test_render_pxe_config_with_local_purpose_amd64_arch(self):
+ # Intel amd64 is a special case and needs to use the chain.c32
+ # loader as the LOCALBOOT PXE directive is unreliable.
+ options = {
+ "arch": "amd64",
+ "subarch": factory.make_name("subarch"),
+ "release": factory.make_name("release"),
+ "purpose": "local",
+ "bootpath": factory.make_name("bootpath"),
+ "append": factory.make_name("append"),
+ }
+ output = render_pxe_config(**options)
+ self.assertIn("chain.c32", output)
+ self.assertNotIn("LOCALBOOT", output)
=== modified file 'src/provisioningserver/pxe/tests/test_install_bootloader.py'
--- src/provisioningserver/pxe/tests/test_install_bootloader.py 2012-07-23 13:25:15 +0000
+++ src/provisioningserver/pxe/tests/test_install_bootloader.py 2012-08-13 08:56:21 +0000
@@ -35,7 +35,6 @@
DirExists,
FileContains,
FileExists,
- Not,
)
@@ -58,19 +57,20 @@
("--config-file", config_fixture.filename, action, "--arch", arch,
"--subarch", subarch, "--loader", loader))
+ bootloader_filename = os.path.join(
+ os.path.dirname(compose_bootloader_path(arch, subarch)),
+ os.path.basename(loader))
self.assertThat(
locate_tftp_path(
- compose_bootloader_path(arch, subarch),
- tftproot=tftproot),
+ bootloader_filename, tftproot=tftproot),
FileExists())
- self.assertThat(loader, Not(FileExists()))
def test_make_destination_creates_directory_if_not_present(self):
tftproot = self.make_dir()
arch = factory.make_name('arch')
subarch = factory.make_name('subarch')
dest = make_destination(tftproot, arch, subarch)
- self.assertThat(os.path.dirname(dest), DirExists())
+ self.assertThat(dest, DirExists())
def test_make_destination_returns_existing_directory(self):
tftproot = self.make_dir()
@@ -78,7 +78,7 @@
subarch = factory.make_name('subarch')
make_destination(tftproot, arch, subarch)
dest = make_destination(tftproot, arch, subarch)
- self.assertThat(os.path.dirname(dest), DirExists())
+ self.assertThat(dest, DirExists())
def test_install_bootloader_installs_new_bootloader(self):
contents = factory.getRandomString()
Follow ups