14. 06. 2025 Alessandro Valentini DevOps, NetEye

How to Add a Drive Selector to an ISO Image

Our old ISO used the first drive (sda) as the only option when installing the system. Sometimes we were asked to install NetEye on a different drive, so as a workaround we suggested properly sorting RAID arrays in the controller, in order to put the installation drive first on the list.

Even if suboptimal, this allowed us to indirectly select the installation disk. But with the spread of NVME drives and new controllers (like Dell BOSS), we can’t assume any longer that an sd* will be present, so we decided to add a drive selector to our ISO.

The Kickstart File

There is no built-in feature in the kickstart file to achieve this, but we can add shell scripts to it.

First we implemented a custom script that allows us to list and select drives using the powerful lsblk command which also lets us select which information to show:

lsblk -nd --output NAME,VENDOR,MODEL,SIZE | grep -e vd -e sd -e nvme -e hd

In this example we print the name of the drive (e.g. sda/sdb/nvme0 etc…), the manufacturer, model and size in order to allow the user to properly identify the drive to be used, and filtering out unwanted types: we don’t want for example to show CDROMs, RAM disks etc…

Of course we added some nice fail-safe mechanisms to prevent user errors, show banners and ask for confirmation. So in the end the script looks like this:

echo "
   _   _      _   ______             _____           _        _ _       _   _
  | \ | |    | | |  ____|           |_   _|         | |      | | |     | | (_)
  |  \| | ___| |_| |__  _   _  ___    | |  _ __  ___| |_ __ _| | | __ _| |_ _  ___  _ __
  |     |/ _ \ __|  __|| | | |/ _ \   | | |  _ \/ __| __/ _  | | |/ _  | __| |/ _ \|  _ \'
  | |\  |  __/ |_| |___| |_| |  __/  _| |_| | | \__ \ || (_| | | | (_| | |_| | (_) | | | |
  |_| \_|\___|\__|______\__, |\___| |_____|_| |_|___/\__\__,_|_|_|\__,_|\__|_|\___/|_| |_|
                         __/ |
                         |___/
"
echo
echo

VALID=false
DRIVES_FILE="/tmp/drives"

while [ "$VALID" = false ]; do
  lsblk -nd --output NAME,VENDOR,MODEL,SIZE | grep -e vd -e sd -e nvme -e hd > ${DRIVES_FILE}
  i=1

  echo "  Please select one of the following drives to install NetEye:"

  while read DRIVE; do
    echo "    ${i} -> ${DRIVE}"
    i=$((i+1))
  done < ${DRIVES_FILE}

  read -p "  drive: " CHOICE

  if [ ${CHOICE} -gt 0 ] && [ ${CHOICE} -lt ${i} ]; then
    SELECTED_DRIVE=$(sed -n ${CHOICE}p ${DRIVES_FILE} | awk '{print $1;}')
    echo "  Selected disk: ${SELECTED_DRIVE}"

    read -p "  Are you sure? (y/N) " CONFIRMATION
    echo
    if [[ ${CONFIRMATION} =~ ^[Yy]$ ]]; then
      VALID=true
    fi

  else
    echo "  Invalid drive!"
  fi
done

Nice, but how do we pass the selected drive to the kickstart file itself? The kickstart file doesn’t allow for the use of user-defined variables, but it does let us write files! So we calculate the desired directives to be included and write them to temporary files:

echo "ignoredisk --only-use=${SELECTED_DRIVE}" > /tmp/ignoredisk
echo "bootloader --append=\" crashkernel=auto\" --location=mbr --boot-drive=${SELECTED_DRIVE}" > /tmp/bootloader

All these parts must be done inside a %pre section, so that the user is prompted and the files are written before the actual installation, and then outside the %pre we can include those files:

%include /tmp/ignoredisk
%include /tmp/bootloader

Now we have our beautiful selector and a way to include the desired directives. So we build the ISO, boot it and… nothing was shown and the ISO was left hanging!

That’s because kickstart uses tty1 to perform the installation. But the user can’t interact with that, so we need to switch consoles to tty6 to allow the user to perform the selection, and then switch back to tty1 to continue the installation.

So in the end our kickstart file is structured like this:

%pre
# Switch to tty6 so the user can prompt
exec < /dev/tty6 > /dev/tty6 2> /dev/tty6
chvt 6
# Our beautiful script

# Switch back to the original terminal
chvt 1
exec < /dev/tty1 > /dev/tty1 2> /dev/tty1
%end

# Include the expected results
%include /tmp/ignoredisk
%include /tmp/bootloader

# Do the partitioning and other stuff (we included the ignoredisk --only-use=... so everything will be done on the selected drive)

%packages
# Install NetEye packages
%end

%post
# Do stuff on the installed system
%end

And with this implementation we have a simple way to perform an interactive installation.

Conclusion

This approach doesn’t just apply to disk selector, but in general you can implement whatever you want and generate part of the kickstart based on user input: for example select dnf groups, change settings, etc…

We used a similar solution to add open-vm-tools only when installing on virtual machines:

if dmidecode | grep -i vmware > /dev/null ; then
    echo "open-vm-tools" > /tmp/vmwaretools
else
    echo "" > /tmp/vmwaretools
fi

In this case there is no interaction with the user, but we still use a shell script + temporary file + %include to handle different behaviors according to the machine we’re running on.

These Solutions are Engineered by Humans

Did you find this article interesting? Are you an “under the hood” kind of person? We’re really big on automation and we’re always looking for people in a similar vein to fill roles like this one as well as other roles here at Würth Phoenix.

Alessandro Valentini

Alessandro Valentini

DevOps Engineer at Wuerth Phoenix
DevOps Engineer at Würth Phoenix

Author

Alessandro Valentini

DevOps Engineer at Würth Phoenix

Leave a Reply

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

Archive