Preseed can be used to fully automate most Ubuntu deployments, but sometimes it needs a little help

Ubuntu installer interface selection screen using only preseed to bypass prompt
Unfortunately preseed alone cannot bypass this prompt if you have more than 1 physical nic connected.

I can usually get preseed to deploy the settings I want in an unattended fashion. That being said, for whatever reason, any time I have an environment that deviates from the norm either the Ubuntu interface selection or the partitioning prompts will cause me some frustration. A few weeks ago, I was deploying some bare metal systems to create a local Kubernetes cluster and ran into the prompt shown at the top of the page. I wasn’t able to effectively utilize the same workarounds I used in Ubuntu 14.04 with Ubuntu 16.04. I’m pretty happy with the solution I ended up with and since I wasn’t able to find all the information I needed in one place, I thought I’d share this fix with you.

Previous workarounds for Ubuntu interface selection

In the past I’ve bypassed the selection prompt by setting my Ubunutu profiles to pass the kernel parameter interface=eth0 as well as hard-coding d-i netcfg/choose_interface eth0 into my preseed file. Hard-coding values are never ideal, but it worked well enough for my environment so it stayed that way for a couple of years. The adoption of predictable interface names has essentially broken this approach. Now if I wanted a one touch menu item, I would have to have multiple profiles with different preseed files for each interface name. In the past, I have had over 20 different physical machines types in my lab.

Another method that I have used when I have had to turn around an environment in a hurry was to simply disable any additional ports from the switch side and set choose_interface to auto in the preseed file. Auto will select the first interface in the alphabetized list with an active link. I really wish the installer would default to the interface that was used for netboot, but that’s not currently the case.

Finding the documentation

The official Ubuntu documentation lists examples of how to setup a netboot install. The use cases and their descriptions can be found here. The main take away is that we need to pass the ksdevice and bootif kernel parameters to make it work. Luckily for us, cobbler has fantastic default configurations that handle this work.

Population of the bootif parameter is actually handled by setting ipappend 2. Setting ipappend 2 automatically populates bootif with the mac address of the interface that requested pxeboot pre-pended with the hardware type(01). This will end up looking like 01-. If you want to read more about the ipappend setting I would recommend looking at the syslinux config options. To see where cobbler actually applies ipappend, you can look through the /etc/cobbler/pxe/ directory. The most notable file to check would probably be pxeprofile.template.

Cobbler sets ksdevice=bootif in /etc/cobbler/settings under the kernel_options section, as shown below. If you had any additional kernel options you wanted to set globally, this would be the spot to do it.

 ksdevice: bootif
 lang: ' '
 text: ~

So the good news is that these two settings will ensure that the correct interface is used to download the kickstart file, but the bad news is that it won’t bypass the interface selection prompt for us. The last setting needed is the interface kernel parameter. I was only able to find this in random forums posts and the source code of the netcfg package. An example tftpboot file is shown below with all 3 relevant settings bolded.

[root@cobbler ~]$ cat /var/lib/tftpboot/pxelinux.cfg/01-90-e2-ba-2e-b0-70
default linux
prompt 0
timeout 1
label linux
kernel /images/Ubuntu-16.04-x86_64/linux
ipappend 2
append initrd=/images/Ubuntu-16.04-x86_64/initrd.gz ksdevice=bootif lang= interface=enp22s0f0 text auto-install/enable=true priority=critical url= hostname=x3630m4001 domain=local.lan suite=xenial

Putting it all together

Now that all the necessary settings were identified, I needed a way to consistently pass the correct interface name. By default, cobbler will append kernel parameters that are set using the kopts flag. So to populate the interface=enp22s0f0 option shown above I had to run the following command cobbler system edit --name=x3630m4001 --kopts="interface=enp22s0f0". Alternatively you can also provide the mac address in-place of the interface name
cobbler system edit --name=x3630m4001 --kopts="interface=90:e2:ba:2e:b0:70"

You can also set the interface name on a profile level, but if you have multiple hardware types, predictable interface names would make it necessary to create separate profiles for each unique interface name.

Personally, I use really basic bash scripts to create individual system profiles. I especially find this method handy because it enables me to easily add custom kickstart variables with using the ksmeta flag. I like to keep my kickstart and preseed files as reusable as possible and ksmeta variables are the key to making it happen. A very basic example script is provided below that reads from a space delimited file named hostlist.file with the hostname, mac address, ip, interface name, mask and gateway of the systems you wish to create profiles for. You can’t set kopts from the cobbler system add option so the kernel option has to be set with an additional cobbler system edit command.

# An example script that creates cobbler system profiles from a file named hostlist.file 
cobbler system add --name=$NAME --interface=$INT --mac=$MAC --ip-address=$IP --netmask=$MASK
--static=1 --dns-name=${NAME} --profile=Ubuntu-16.04-x86_64-efi --gateway=$GATE

# Example of adding ksmeta variables without overriding existing variables
# cobbler system edit --name=$NAME --in-place --ksmeta="bootdev=/dev/sde, clustervip=" 

cobbler system edit --name=$NAME --kopts="interface=${MAC}"
done < hostlist.file

Additional thoughts on Ubuntu interface selection

I find it unfortunate that you can’t just set interface=bootif as a kernel parameter. I tried and the variable won’t substitute and instead will just attempt to bring up a non-existent interface named bootif. Bootif provides the mac address in a very consumable format, dash delimited mac address pre-pended by hardware type, which would probably make it fairly straightforward to add support to the interface flag through the netcfg package, so who knows maybe it’ll show up as a supported feature one day in the future.


Learn more about Linux on developerWorks




Join The Discussion

Your email address will not be published. Required fields are marked *