How to Netboot with iPXE Part 3

Peter Bolch
5 min readJun 3, 2022

--

Creating a menu and failure handling

Photo by Rostyslav Savchyn on Unsplash

In “How to Netboot with iPXE Part 2: Booting Alpine” we’ve learned how to boot Alpine Linux by providing a iPXE boot script over http.

What will I learn

  • Create a menu with iPXE to choose Alpine version
  • Add some error handling to the iPXE script

Prerequisites

For simplicity we provide the iPXE boot script over an HTTP Server. This is useful because you don’t have to build your iso image everytime you want to test a changed iPXE script. I described the setup in “How to netboot with iPXE Part 1: Basics” and “How to Netboot with iPXE Part 2: Booting Alpine”. Short: Use a the python http module to provide a iPXE script (as text) over HTTP. Build an iPXE.iso which loads this iPXE script.

Choose Alpine version by Menu

Now we want to implement a menu in iPXE to choose between the Alpine lts orthe virt version.

This is particularly useful if we want to give a user the opportunity to choose which OS is going to be loaded or to choose between different options. Furthermore we can repeat some stuff of “How to netboot with iPXE Part 1: Basics” . Namely: variables, prompts, marker and goto command.

Let’s start with a simple menu, paste this into your alpine_boot.ipxe file.

#!ipxe
menu what do you want to be prompted
item hw Hello World!
item hb Hello Bob!
choose text_to_display && echo ${text_to_display}

Start qemu and you should see this

Choose one of the options, then you should see this.

So, what happens?

In the first line we specify a menu and a text which is shown as headline. After that we specify the items in the form

item <label> <text>

text is shown as menu item and label is saved into a “setting variable”. Saving into a setting variable is accomplished with the choose command:

choose <setting>

After that we simply prompt the variable with the echo command.

&& echo ${text_to_display}

Now let’s use this to choose the version of Alpine by setting a version variable and replacing the lts in the url with the variable ${version}

Hint: If you have problems following these steps please look at “How to netboot with iPXE Part 1: Basics” and “How to Netboot with iPXE Part 2: Booting Alpine

#!ipxe
set local_address http://10.0.2.2:5001
set alpine_repo http://dl-cdn.alpinelinux.org/alpine/v3.15/main
:start
menu Please choose an operating system to boot
item lts Alpine LTS
item virt Alpine Virt
choose version
kernel ${local_address}/vmlinuz-${version} ip=dhcp alpine_repo=${alpine_repo} modloop=${local_address}/modloop-${version} initrd=initramfs-${version}
initrd ${local_address}/initramfs-${version}
boot

Now you can choose between the lts and the virt version of Alpine.

Failure handling

Until now, we’ve not talked about failure handling so lets destroy our script by deleting the local_address

...
set local_address http://localhost
....

Lets see what happens by starting qemu again. We see this

Now we can do nothing except reboot qemu. This is definitely not what we want. For this reason, we can use the || operator. By adding || at the end of the lines which are loading kernel and initramfs iPXE simply says: “Okay, there was an error loading these files, but I’m good with it, I keep going and process the rest of the script.”

Finally after failing we get to the boot command. We have no kernel and no initramfs and therefore nothing to boot so iPXE goes on with processing. Now we have to implement some failure handling because nothing happens when the boot command is executed. A simple way to handle this is to use the goto command and going back to the :start label above the menu. This is okay because maybe the choosen option was broken and we simply can use the other one.

Finally we want to add prompts to tell the user what happens. Furthermore we need a sleep of several seconds because otherwise the prompt disappears to fast. We will end up with this script:

#!ipxe
set local_address http://10.0.2.2:5001
set alpine_repo http://dl-cdn.alpinelinux.org/alpine/v3.15/main
:start
menu Please choose an operating system to boot
item lts Alpine LTS
item virt Alpine Virt
choose version
kernel ${local_address}/vmlinuz-${version}-- ip=dhcp alpine_repo=${alpine_repo} modloop=${local_address}/modloop-${version} initrd=initramfs-${version} ||
initrd ${local_address}/initramfs-${version} ||
boot
echo Loading failed
echo Going back to menu in 4 seconds
sleep 4
goto start

You can test the error handling by yourself by destroying the local_address again and starting qemu. You should see this:

After 4 seconds you will see the menu again.

Final thoughts

We’ve created a menu to choose the Alpine version and brought some error handling into place. With the iPXE commands one can build more complex menus. A good example is the official Alpine Linux iPXE script.

Whats next?

In Part 4 we will learn how to use url parameters to automatically decide which version of Alpine is delivered. This is usefeul if you have several devices in the wild and each of them needs a os with another version and another set of software. With url params the HTTP server can decide which os is delivered. Here we need some logic at the server side and therefore I will use Python with Flask.

--

--