diff --git a/debian/ostree-boot-examples/README.md b/debian/ostree-boot-examples/README.md new file mode 100644 index 00000000..bf08b726 --- /dev/null +++ b/debian/ostree-boot-examples/README.md @@ -0,0 +1,93 @@ +# Testing ostree-boot on an existing system + +Start from an amd64 Debian system (9 or newer, as long as a backported +ostree-boot package is available) - it will be switched to a Debian +unstable (sid) OSTree-based installation as part of following these +instructions. A VM is obviously most convenient, but bare metal should +work equally. + +The installation needs to satisfy the following requirements: + +* It must have a separate /boot partition (this is a general libostree + limitation [1]). +* The root partition must not be encrypted. +* It must use GRUB and BIOS booting. Other bootloaders or EFI may require + different bootloader setup steps. [2] + +[1]: https://github.com/ostreedev/ostree/issues/1452 +[2]: https://pagure.io/workstation-ostree-config/blob/5b574d39c63b82b397df789eb4a75a5bdcc13dd0/f/README-install-inside.md + +We need the bootloader integration files on the non-OSTree system from +which we are switching, as well as in the OSTree-based installation, +so the bootloader gets configured properly when we "ostree admin deploy": + + # apt-get update + # apt-get install ostree ostree-boot multistrap + +Create the ostree system repository and a stateroot: + + # ostree admin init-fs / + # ostree admin os-init debian + +Copy modified-deb-ostree-builder, ostree-1.conf and ostree-2.conf from +debian/ostree-boot-examples/ to the test machine, and run the builder +script: + + # chmod +x ./deb-ostree-builder + # ./deb-ostree-builder ./ostree-1.conf sid-1 /ostree/repo + # ./deb-ostree-builder ./ostree-2.conf sid-2 /ostree/repo + +If ostree-boot is not available in the target suite in the Debian +archive yet, then you will need to edit ostree-1.conf and ostree-2.conf to +remove ostree-boot from the bootstrap, and instead put the ostree-boot, +ostree and libostree-1-1 packages in /root/extra-packages, and use +modified-deb-ostree-builder instead of deb-ostree-builder. This is a +temporary hack to solve the chicken-and-egg situation of not adding +ostree-boot to the Debian archive until it is testable, but not being +able to test it until it is in the archive. + +Then we deploy the first of those commits: + + # ostree admin deploy --karg-proc-cmdline --os=debian os/debian/amd64/sid-1 + # deploy=$(find /ostree/deploy/debian/deploy/* -maxdepth 0 -type d) + +Next, we set the root password and copy a few essential configuration files +into the initial deployment: + + # chroot $deploy passwd root + # : > $deploy/etc/machine-id + # for f in etc/fstab etc/default/grub; do cp /$f $deploy/$f; done + +Finally, we set up the bootloader by pointing GRUB at the configuration file +managed by ostree. Alternatively, you can run update-grub by hand after every +new ostree deployment. This step may be different or unnecessary for other +bootloaders. + + # mv /boot/grub/grub.cfg /boot/grub/grub.cfg.backup + # ln -s ../loader/grub.cfg /boot/grub/grub.cfg + +Now reboot. Make sure to select the new ostree entry in the bootloader. Log in +as root using the password you selected before. The system is rather +unconfigured (network access can be set up in /etc/network/interfaces). This is +the commit built from the ostree-1.conf file, so it doesn't have the hello +package: + + # hello + -bash: hello: command not found + +Now we can deploy the second commit from inside the ostree system: + + # ostree admin deploy --karg-proc-cmdline --os=debian os/debian/amd64/sid-2 + +Reboot again. Note that your new deployment will again be the first ostree +entry in the menu, labelled `ostree:0`. Your old deployment has been moved +down the menu to `ostree:1`. The root password and the other configuration +was copied from the first deployment, so you can log in as before. + +Now try running the hello command again: + + # hello + Hello, world! + +This shows we've now booted the second commit built from ostree-2.conf, which +includes the hello package. diff --git a/debian/ostree-boot-examples/deb-ostree-builder b/debian/ostree-boot-examples/deb-ostree-builder new file mode 100644 index 00000000..7dc9d2de --- /dev/null +++ b/debian/ostree-boot-examples/deb-ostree-builder @@ -0,0 +1,309 @@ +#!/bin/bash -e + +# deb-ostree-builder - Build bootable Debian OSTree commits +# +# Copyright (C) 2017 Dan Nicholson +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +PROG=$(readlink -f "$0") +PROGDIR=$(dirname "$PROG") + +# Defaults +ARCH=$(dpkg --print-architecture) +BUILDDIR= +GPG_SIGN=() +GPG_HOMEDIR= + +usage() { + cat <&2 + exit 1 +fi + +CONFIG=$1 +SUITE=$2 +REPO=$3 + +# Mount cleanup handler +DEVICES_MOUNTED=false +cleanup_mounts() +{ + if $DEVICES_MOUNTED; then + echo "Unmounting filesystems in $BUILDDIR" + for dir in dev/pts dev sys proc; do + umount "$BUILDDIR/$dir" + done + DEVICES_MOUNTED=false + fi +} + +# Exit handler +TMP_BUILDDIR= +cleanup() +{ + cleanup_mounts || true + if [ -n "$TMP_BUILDDIR" ]; then + rm -rf "$TMP_BUILDDIR" + fi +} +trap cleanup EXIT + +if [ -n "$BUILDDIR" ]; then + # Create specified build directory + echo "Creating $BUILDDIR" + mkdir -p "$BUILDDIR" +else + # Create a temporary build directory in /var/tmp since it could be + # fairly large + TMP_BUILDDIR=$(mktemp -d -p /var/tmp deb-ostree-builder-XXXXXXXX) + BUILDDIR=$TMP_BUILDDIR + echo "Using temporary directory $BUILDDIR for build" +fi + +# Ensure that dracut makes generic initramfs instead of looking just +# at the host configuration. This is also in the dracut-config-generic +# package, but that only gets installed after dracut makes the first +# initramfs. +echo "Configuring dracut for generic initramfs" +mkdir -p "$BUILDDIR"/etc/dracut.conf.d +cat > "$BUILDDIR"/etc/dracut.conf.d/90-deb-ostree.conf < "$BUILDDIR"/usr/sbin/policy-rc.d </dev/null + +vmlinuz_match=(vmlinuz*) +vmlinuz_file=${vmlinuz_match[0]} +initrd_match=(initrd.img* initramfs*) +initrd_file=${initrd_match[0]} + +csum=$(cat ${vmlinuz_file} ${initrd_file} | \ + sha256sum --binary | \ + awk '{print $1}') +echo "OSTree boot checksum: ${csum}" + +mv ${vmlinuz_file} ${vmlinuz_file}-${csum} +mv ${initrd_file} ${initrd_file/initrd.img/initramfs}-${csum} + +popd >/dev/null + +# OSTree only commits files or symlinks +rm -rf "$BUILDDIR"/dev +mkdir -p "$BUILDDIR"/dev + +# Fixup home directory base paths for OSTree +sed -i -e 's|DHOME=/home|DHOME=/sysroot/home|g' \ + "${BUILDDIR}"/etc/adduser.conf +sed -i -e 's|# HOME=/home|HOME=/sysroot/home|g' \ + "${BUILDDIR}"/etc/default/useradd + +# Move /etc to /usr/etc. +# +# FIXME: Need to handle passwd and group to be updatable. This can be +# done with libnss-altfiles, though that has other drawbacks. +if [ -d "${BUILDDIR}"/usr/etc ]; then + echo "ERROR: Non-empty /usr/etc found!" >&2 + ls -lR "${BUILDDIR}"/usr/etc + exit 1 +fi +mv "${BUILDDIR}"/etc "${BUILDDIR}"/usr + +# Move dpkg database to /usr so it's accessible after the OS /var is +# mounted, but make a symlink so it works without modifications to dpkg +# or apt +mkdir -p "${BUILDDIR}"/usr/share/dpkg +if [ -e "${BUILDDIR}"/usr/share/dpkg/database ]; then + echo "ERROR: /usr/share/dpkg/database already exists!" >&2 + ls -lR "${BUILDDIR}"/usr/share/dpkg/database >&2 + exit 1 +fi +mv "${BUILDDIR}"/var/lib/dpkg "${BUILDDIR}"/usr/share/dpkg/database +ln -sr "${BUILDDIR}"/usr/share/dpkg/database \ + "${BUILDDIR}"/var/lib/dpkg + +# tmpfiles.d setup to make the ostree root compatible with persistent +# directories in the sysroot. +cat > "${BUILDDIR}"/usr/lib/tmpfiles.d/ostree.conf < +# Copyright (C) 2019 Simon McVittie +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +PROG=$(readlink -f "$0") +PROGDIR=$(dirname "$PROG") + +# Defaults +ARCH=$(dpkg --print-architecture) +BUILDDIR= +GPG_SIGN=() +GPG_HOMEDIR= + +usage() { + cat <&2 + exit 1 +fi + +CONFIG=$1 +SUITE=$2 +REPO=$3 + +# Mount cleanup handler +DEVICES_MOUNTED=false +cleanup_mounts() +{ + if $DEVICES_MOUNTED; then + echo "Unmounting filesystems in $BUILDDIR" + for dir in dev/pts dev sys proc; do + umount "$BUILDDIR/$dir" + done + DEVICES_MOUNTED=false + fi +} + +# Exit handler +TMP_BUILDDIR= +cleanup() +{ + cleanup_mounts || true + if [ -n "$TMP_BUILDDIR" ]; then + rm -rf "$TMP_BUILDDIR" + fi +} +trap cleanup EXIT + +if [ -n "$BUILDDIR" ]; then + # Create specified build directory + echo "Creating $BUILDDIR" + mkdir -p "$BUILDDIR" +else + # Create a temporary build directory in /var/tmp since it could be + # fairly large + TMP_BUILDDIR=$(mktemp -d -p /var/tmp deb-ostree-builder-XXXXXXXX) + BUILDDIR=$TMP_BUILDDIR + echo "Using temporary directory $BUILDDIR for build" +fi + +# Ensure that dracut makes generic initramfs instead of looking just +# at the host configuration. This is also in the dracut-config-generic +# package, but that only gets installed after dracut makes the first +# initramfs. +echo "Configuring dracut for generic initramfs" +mkdir -p "$BUILDDIR"/etc/dracut.conf.d +cat > "$BUILDDIR"/etc/dracut.conf.d/90-deb-ostree.conf < "$BUILDDIR"/usr/sbin/policy-rc.d </dev/null + +vmlinuz_match=(vmlinuz*) +vmlinuz_file=${vmlinuz_match[0]} +initrd_match=(initrd.img* initramfs*) +initrd_file=${initrd_match[0]} + +csum=$(cat ${vmlinuz_file} ${initrd_file} | \ + sha256sum --binary | \ + awk '{print $1}') +echo "OSTree boot checksum: ${csum}" + +mv ${vmlinuz_file} ${vmlinuz_file}-${csum} +mv ${initrd_file} ${initrd_file/initrd.img/initramfs}-${csum} + +popd >/dev/null + +# OSTree only commits files or symlinks +rm -rf "$BUILDDIR"/dev +mkdir -p "$BUILDDIR"/dev + +# Fixup home directory base paths for OSTree +sed -i -e 's|DHOME=/home|DHOME=/sysroot/home|g' \ + "${BUILDDIR}"/etc/adduser.conf +sed -i -e 's|# HOME=/home|HOME=/sysroot/home|g' \ + "${BUILDDIR}"/etc/default/useradd + +# Move /etc to /usr/etc. +# +# FIXME: Need to handle passwd and group to be updatable. This can be +# done with libnss-altfiles, though that has other drawbacks. +if [ -d "${BUILDDIR}"/usr/etc ]; then + echo "ERROR: Non-empty /usr/etc found!" >&2 + ls -lR "${BUILDDIR}"/usr/etc + exit 1 +fi +mv "${BUILDDIR}"/etc "${BUILDDIR}"/usr + +# Move dpkg database to /usr so it's accessible after the OS /var is +# mounted, but make a symlink so it works without modifications to dpkg +# or apt +mkdir -p "${BUILDDIR}"/usr/share/dpkg +if [ -e "${BUILDDIR}"/usr/share/dpkg/database ]; then + echo "ERROR: /usr/share/dpkg/database already exists!" >&2 + ls -lR "${BUILDDIR}"/usr/share/dpkg/database >&2 + exit 1 +fi +mv "${BUILDDIR}"/var/lib/dpkg "${BUILDDIR}"/usr/share/dpkg/database +ln -sr "${BUILDDIR}"/usr/share/dpkg/database \ + "${BUILDDIR}"/var/lib/dpkg + +# tmpfiles.d setup to make the ostree root compatible with persistent +# directories in the sysroot. +cat > "${BUILDDIR}"/usr/lib/tmpfiles.d/ostree.conf <