add packages to subiquity based installation

Solution 1:

I've also been working at this but for ubuntu live server 20.04. I don't know if it applies for Ubuntu Desktop.

The idea is to rebuild the iso after modifying casper/filesystem.squashfs and setting up subiquity/autoinstall. But sometimes, pre-installing some packages seems to break the installer (like ifenslave package) so I install those packages in the late stages of auto-install.

So to pre-install some packages on the iso you have two possibilites :

Modify capser/filesystem.squashfs

The general idea is to :

  1. mount the original live iso
  2. mount casper/filesystem.squashfs
  3. chroot and install your packages
  4. repack the new casper/filesystem.squashfs
  5. update some other files on the iso
  6. rebuild the iso

Some references I've used :

[1] https://medium.com/100-days-of-linux/chroot-a-linux-wonder-fc36ed08087e : Putting up subiquity/autoinstall for automated install, nocloud style

[2] https://github.com/ljfranklin/ubuntu-img-builder/blob/master/build.sh : Script demonstrating capser/filesystem.squashfs modification

[3] https://github.com/canonical/subiquity/blob/main/scripts/inject-subiquity-snap.sh#L194 : great script from canonical subiquity demonstrating how practical overlayfs is and a simplified xorriso usage

Install packages in late stages of autoinstall

The idea here is to use apt to download the packages and the missing dependencies and install them later during autoinstall late-command stage. It would imply the following steps :

  1. mount the original live iso.
  2. mount casper/filesystem.squashfs.
  3. chroot and use apt-get install --download-only -y -o Dir::Cache="/yourcache" -o Dir::Cache::archives="archives/" ${listOfPackages}. This will download the targeted packages and their dependencies missing from filesystem.squashfs.
  4. Setup subiquity autoinstall to install those packages at the end of autoinstall procedure like below : I tried to use apt install by specifying the cache dir but doesn't work with curtin. So instead I use dpkg --unpack *.deb; apt-get install --no-download -yf. It's not as clean as using apt but for me it did the job
#cloud-config
autoinstall:
version: 1
interactive-sections:
# ...
late-commands:
    - curtin in-target --target=/target -- bash -c 'cd /yourcache/archives; dpkg --unpack *.deb; apt-get install --no-download -yf'
    # - curtin in-target --target=/target -- bash -c 'apt-get install --print-uris --no-download -y -f -o Dir::Cache="/awrepo" -o Dir::Cache::archives="archives/" __PARAM_PACKAGES_POST__' # doesn't work. use dpkg --unpack instead
    - curtin in-target --target=/target -- apt-get --purge -y --quiet=2 autoremove
    - curtin in-target --target=/target -- apt-get clean

Here is the gist of all this put together : https://gist.github.com/creatldd1/eec887f3f8a0bf48e0e9dec1598b8614

NB : An alternative to local apt cache would be to build a local apt repo on the iso and configure apt to use it. The problem is that the size of the repo can be huge. It was my first approach but I gave it up.

Great link to configure a simple repo : https://unix.stackexchange.com/a/595448/402499.

The code to download the package and its dependencies, recursively :

listPkg=$(apt-cache depends --recurse --no-recommends --no-suggests --no-conflicts --no-breaks ${theListofPackages} | grep "^\w" | sort --unique )
for pkg in ${listPkg}
do
    if ! apt-get download ${pkg}; then
        echo >&2 " WARNING : problem fetching package ${pkg}. Keeping on"
    fi
done

More info on that, check https://stackoverflow.com/questions/22008193/how-to-list-download-the-recursive-dependencies-of-a-debian-package