Add support for building grml ISOs with zfs
authorAndrás Korn <korn-github.com@elan.rulez.org>
Sun, 21 Aug 2022 08:38:22 +0000 (10:38 +0200)
committerAndrás Korn <korn-github.com@elan.rulez.org>
Sun, 21 Aug 2022 08:38:22 +0000 (10:38 +0200)
The `ZFS` FAI class will, via the `instsoft.ZFS` hook, install the packages
needed to build the zfs modules, build the zfs modules, then remove the
development packages again to avoid bloating the ISO. The ZFS
`package_config` now only installs `zfsutils-linux` so that the iso contains
the userspace zfs tools.

In my tests, the ZFS class now only increases the size of the ISO by about
3MB.

I wanted to rely on apt autoremove to get rid of automatically installed
packages, but for some reason as of 2.5.2 autoremove doesn't actually remove
some of the development packages (e.g. gcc-11) even though they're Priority
optional, marked as auto-installed, and not depended on by anything that
isn't auto-installed.

So, to avoid bloating the ISO with hundreds of MB of development packages,
the `instsoft.ZFS` script works out which packages it installs and removes
those explicitly, using potentially brittle parsing of `apt-get` output.
This has been tested to work and should do until a better solution is found.

etc/grml/fai/config/hooks/instsoft.ZFS [new file with mode: 0755]
etc/grml/fai/config/package_config/ZFS

diff --git a/etc/grml/fai/config/hooks/instsoft.ZFS b/etc/grml/fai/config/hooks/instsoft.ZFS
new file mode 100755 (executable)
index 0000000..2e8a072
--- /dev/null
@@ -0,0 +1,81 @@
+#!/bin/bash
+# Filename:      ${GRML_FAI_CONFIG}/hooks/instsoft.ZFS
+# Purpose:       Build zfs modules in the chroot, then get rid of packages installed for this alone
+# Authors:       (c) András Korn <korn-grml@elan.rulez.org>
+# Bug-Reports:   see http://grml.org/bugs/
+# License:       This file is licensed under the GPL v2, or, at your option, any later version.
+################################################################################
+
+set -u
+set -e
+
+# We don't want to install build-essential, dkms et al via package_config
+# because they will end up bloating the iso; it seems cleaner to install
+# them, build the zfs modules, then remove them.
+#
+# TODO: if https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1009179 is ever
+# fixed, switch to building a zfs-modules deb and including that.
+#
+# TODO: convert this into a framework for other classes to ship dkms
+# modules: have a hook/script that installs the build-related packages,
+# another that builds whatever must be built, and a third that does the cleanup.
+#
+# TODO: support other architectures grml and grml-live supports (PRs
+# welcome, I'm sure).
+
+echo "$0: Installing latest kernel and its headers, as well as build-essential."
+# For some reason, apt's autoremove function doesn't pick up some of the
+# extra packages we install here, e.g. gcc-11, so work around that by
+# keeping track of what gets installed. This is an ugly hack and should not
+# be needed, but without it the resulting ISO is hundreds of megabytes
+# larger. I hope this kludge can go away eventually.
+extra_packages=($($ROOTCMD apt-get --assume-no --download-only --mark-auto -u install \
+       build-essential linux-image-amd64 linux-headers-amd64 \
+       | sed '0,/The following NEW packages will be installed/d;/^[^ ]/,$d'))
+$ROOTCMD apt-get --yes --mark-auto -u install build-essential linux-image-amd64 linux-headers-amd64
+
+# Remove all but the latest kernel (TODO: support passing in the desired
+# kernel version by configuration variable instead of using the latest):
+echo "$0: Removing all kernel packages except the latest one, if any."
+for kernelversion in $($ROOTCMD sh -c 'cd /boot; ls -rt vmlinuz-*' | sed 's/^vmlinuz-//;$d'); do
+       echo "$0: Removing obsolete kernel version $kernelversion"
+       $ROOTCMD apt-get --yes --purge remove "linux-.*$kernelversion.*"
+done
+
+# Earlier Debian releases have a dwarves package; newer ones have pahole.
+# This can be needed to build the zfs modules, perhaps depending on kernel
+# configuration (TODO: look into this).
+echo "$0: Installing pahole or dwarves, whichever is available."
+if $ROOTCMD apt-get --yes --mark-auto -u install pahole; then
+       pahole=pahole
+else
+       $ROOTCMD apt-get --mark-auto --yes -u install dwarves
+       pahole=dwarves
+fi
+
+echo "$0: Installing zfs-dkms itself."
+extra_packages=(${extra_packages[@]} $($ROOTCMD apt-get --assume-no --download-only --mark-auto -u install zfs-dkms | sed '0,/The following NEW packages will be installed/d;/^[^ ]/,$d'))
+$ROOTCMD apt-get --yes --mark-auto -u install zfs-dkms
+
+# Now invoke the dkms kernel postinst script for the only kernel that's left
+# -- normally the zfs-dkms postinst script should do this, but maybe it
+# didn't, and redoing it is almost free:
+kernelversion=$($ROOTCMD sh -c 'ls -1 /boot/vmlinuz-*' | sed 's@.*boot/vmlinuz-@@')
+echo "$0: Building zfs-dkms modules for kernel $kernelversion."
+$ROOTCMD /etc/kernel/postinst.d/dkms "$kernelversion"
+
+tempfile=$(mktemp)
+echo "$0: Saving built modules into a backup file (removing the dkms package will remove them, but we'll put them back)."
+$ROOTCMD tar cf - /lib/modules/$kernelversion/updates/dkms >$tempfile
+
+echo "$0: Removing packages only needed to build zfs modules."
+remove_packages=($(echo "${extra_packages[@]}" zfs-dkms '^linux-headers-.*' build-essential $pahole | tr ' ' '\n' | sort -u))
+$ROOTCMD apt-get --yes --purge --autoremove remove ${remove_packages[@]}
+echo "$0: Trying extra hard to get rid of auto-installed packages. This is a hack that is one of the ways we're trying to work around a perceived bug in apt autoremove and should be a no-op."
+$ROOTCMD apt-get --yes --purge autoremove
+
+echo "$0: Restoring backed-up kernel modules."
+$ROOTCMD tar xf - <$tempfile
+rm $tempfile
+$ROOTCMD depmod -a $kernelversion
+echo "$0: Completed successfully. Enjoy your zfs."
index c0c2451..02ca370 100644 (file)
@@ -1,9 +1,4 @@
 PACKAGES install
 
-build-essential
-# pahole(1), provided by the dwwarves package in older Debian releases and the pahole package in sid as of 2022-08, can be needed to build kernel modules (depending on kernel config?)
-# TODO: add a script that removes it once dkms install succeeded so that it doesn't bloat the iso
-dwarves
-zfs-dkms
 zfsutils-linux