diff --git a/opennebula-images/freebsd-build-opennebula-image.sh b/opennebula-images/freebsd-build-opennebula-image.sh index af5e6a8..4c4d841 100755 --- a/opennebula-images/freebsd-build-opennebula-image.sh +++ b/opennebula-images/freebsd-build-opennebula-image.sh @@ -2,25 +2,43 @@ # This script generates FreeBSD images for OpenNebula, being heavily inspired # from srht's FreeBSD build image definition. It assumes running on a FreeBSD host. +# ZFS installation as documented by the FreeBSD project +# https://wiki.freebsd.org/RootOnZFS/GPTZFSBoot set -e set -x # XXX: Handle command-line arguments? -RELEASE=13.0-RELEASE +RELEASE=13.1-RELEASE ARCH=amd64 -IMAGE_PATH=freebsd-$RELEASE-$(date -I).img.qcow2 +IMAGE_PATH_ZFS=freebsd-zfs-$RELEASE-$(date -I).img.qcow2 +IMAGE_PATH_UFS=freebsd-ufs-$RELEASE-$(date -I).img.qcow2 IMAGE_SIZE=10G DIST_BASE="https://download.freebsd.org/ftp/releases/$ARCH/$RELEASE" +CLSETUP_COMMIT=82d7d16ff14e1893f06f39788bb7cd8604284583 +CLSETUP_URL="https://git.sr.ht/~jornane/clsetup/archive/$CLSETUP_COMMIT.tar.gz" +ZPOOL=zroot -ONE_CONTEXT_PKG_URL="https://github.com/OpenNebula/addon-context-linux/releases/download/v6.2.0/one-context-6.2.0_1.txz" +ZFSTARGET="$(mktemp -d /var/tmp/zfsbuild.XXXXX)" +UFSTARGET="$(mktemp -d /var/tmp/ufsbuild.XXXXX)" +CLSETUP_WORK="$(mktemp -d /var/tmp/clsetup.XXXXX)" + +if zpool list -Ho name $ZPOOL 2>/dev/null; then + echo "The pool $ZPOOL is already imported." >&2 + exit 1 +fi cleanup() { - sync || true - umount /mnt/dev || true - umount /mnt || true - mdconfig -du md0 || true + sync ||: + umount "$UFSTARGET/dev" ||: + umount "$UFSTARGET/tmp" ||: + umount "$UFSTARGET/var/tmp" ||: + umount "$UFSTARGET" ||: + zpool export $ZPOOL ||: + mdconfig -du md0 ||: + mdconfig -du md1 ||: + rm -rf "$CLSETUP_WORK" } trap cleanup EXIT @@ -29,82 +47,144 @@ if [ "$(whoami)" != 'root' ]; then exit 1 fi -env ASSUME_ALWAYS_YES=YES pkg install -y qemu-tools +if ! command -v rsync >/dev/null +then + env ASSUME_ALWAYS_YES=YES pkg install -y rsync +fi +if ! command -v qemu-img >/dev/null +then + env ASSUME_ALWAYS_YES=YES pkg install -y qemu-tools +fi -# Allocate and partition/format disk image. -disk=$(mktemp) -truncate -s 6G $disk -mdconfig -a -t vnode -f $disk -u md0 -gpart create -s gpt /dev/md0 -gpart add -t freebsd-boot -l bootfs -b 40 -s 512K md0 -gpart bootcode -b /boot/pmbr -p /boot/gptboot -i 1 md0 -gpart add -t freebsd-ufs -l rootfs -b 1M -s 5G md0 -newfs -U /dev/md0p2 +fetch -qo- "$CLSETUP_URL" | tar -C "$CLSETUP_WORK" --strip-components 1 -xzf- + +ufsdisk=$(mktemp /var/tmp/ufsdisk.XXXXX) +truncate -s 6G $ufsdisk +mdconfig -a -t vnode -f $ufsdisk -u md1 +gpart create -s gpt /dev/md1 +gpart add -t freebsd-boot -l bootfs -b 40 -s 512K md1 +gpart bootcode -b /boot/pmbr -p /boot/gptboot -i 1 md1 +gpart add -t freebsd-ufs -l rootfs -b 1M -s 5G md1 +newfs -U /dev/md1p2 # Mount allocated image. -mount /dev/md0p2 /mnt -mkdir -p /mnt/dev -mount -t devfs devfs /mnt/dev +mount /dev/md1p2 "$UFSTARGET" + +# Allocate and partition/format disk image. +# We use "legacy boot", aka BIOS boot +# Preferably, we'd use EFI boot here, check the FreeBSD wiki link in the header +# to see how to make that change, but make the EFI partition larger +zfsdisk=$(mktemp /var/tmp/zfsdisk.XXXXX) +truncate -s 6G $zfsdisk +mdconfig -a -t vnode -f $zfsdisk -u md0 +gpart create -s gpt /dev/md0 +gpart add -t freebsd-boot -l bootfs -b 40 -s 512K md0 +gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 md0 +gpart add -t freebsd-zfs -l zfs0 -b 1M -s 5G md0 +zpool create -O compression=on -o ashift=12 -o altroot="$ZFSTARGET" -m none $ZPOOL md0p2 + +zfs create -o mountpoint=none $ZPOOL/ROOT +# We set zstd-19 so our image will become smaller, at the cost of a longer build time. +# At the end of the process, we disable zstd-19 again using zfs inherit compression, +# but all files already written will remain zstd-19 compressed +zfs create -o mountpoint=/ -o canmount=noauto $ZPOOL/ROOT/default +mount -t zfs $ZPOOL/ROOT/default "$ZFSTARGET" +zpool set bootfs=$ZPOOL/ROOT/default $ZPOOL + +zfs create -o mountpoint=/tmp -o exec=on -o setuid=off $ZPOOL/tmp +zfs create -o canmount=off -o mountpoint=/usr $ZPOOL/usr +zfs create $ZPOOL/usr/home +zfs create -o exec=off -o setuid=off $ZPOOL/usr/src +zfs create -o mountpoint=/usr/ports -o setuid=off $ZPOOL/usr/ports +zfs create -o canmount=off -o mountpoint=/var $ZPOOL/var +zfs create -o exec=off -o setuid=off $ZPOOL/var/audit +zfs create -o exec=off -o setuid=off $ZPOOL/var/crash +zfs create -o exec=off -o setuid=off $ZPOOL/var/log +zfs create -o atime=on -o exec=off -o setuid=off $ZPOOL/var/mail +zfs create -o exec=on -o setuid=off $ZPOOL/var/tmp + +ln -s /usr/home "$ZFSTARGET/home" +chmod 1777 "$ZFSTARGET/var/tmp" +chmod 1777 "$ZFSTARGET/tmp" + +# Mount dev in chroot +mkdir -p "$UFSTARGET/dev" +mount -t devfs devfs "$UFSTARGET/dev" # Download and extract base system. dist_files="kernel.txz base.txz" dist_dir="/usr/freebsd-dist/$ARCH/$RELEASE" -mkdir -p "$dist_dir" +mkdir -p "$dist_dir" "$UFSTARGET" for f in $dist_files do fetch -m -o "$dist_dir/$f" "$DIST_BASE/$f" - tar -C /mnt -xJf "$dist_dir/$f" + tar -C "$UFSTARGET" -xJf "$dist_dir/$f" done +# Avoid writing temporary files while building +mount_nullfs /tmp "$UFSTARGET/tmp" +mount_nullfs /var/tmp "$UFSTARGET/var/tmp" + +# Install the first-boot script that configures the network and ssh key +make -C "$CLSETUP_WORK/" PREFIX="$UFSTARGET/usr/local" install + # Configure new system. -echo "/dev/gpt/rootfs / ufs rw,noatime 1 1" >/mnt/etc/fstab -touch /mnt/firstboot -sysrc -f /mnt/boot/loader.conf autoboot_delay=-1 +printf '# Device\tMountpoint\tFStype\tOptions\t\tDump\tPass#\n' >"$UFSTARGET/etc/fstab" +touch "$UFSTARGET/firstboot" +sysrc -f "$UFSTARGET/boot/loader.conf" \ + zfs_load=YES \ + autoboot_delay=-1 \ -sysrc -f /mnt/etc/rc.conf ntpd_enable=YES sshd_enable=YES growfs_enable=YES hostname=freebsd +sysrc -f "$UFSTARGET/etc/rc.conf" \ + ntpd_enable=YES \ + sshd_enable=YES \ + growfs_enable=YES \ + hostname=freebsd \ + firstboot_clsetup_enable=YES \ -cp /etc/resolv.conf /mnt/etc/resolv.conf -tzsetup -s -C /mnt UTC +# The resolv.conf file is written by firstboot_clsetup +#cp /etc/resolv.conf "$UFSTARGET/etc/resolv.conf" -cat >>/mnt/etc/ssh/sshd_config <>"$UFSTARGET/etc/ssh/sshd_config" </mnt/usr/local/etc/pkg/repos/FreeBSD.conf - # freebsd-update is only supported for RELEASE -if [ "${release%-RELEASE}" != "$RELEASE" ] +if printf %s "$RELEASE" | grep -q '.-RELEASE$' then env PAGER=true /usr/sbin/freebsd-update \ - -b /mnt \ + -b "$UFSTARGET" \ --currently-running "$RELEASE" \ --not-running-from-cron -F \ fetch install - rm -rf /mnt/var/db/freebsd-update/* fi +rm -rf "$UFSTARGET/var/db/freebsd-update/"* ||: -env ASSUME_ALWAYS_YES=YES pkg -c /mnt bootstrap -f - -fetch -m -o /mnt/one-context.txz "$ONE_CONTEXT_PKG_URL" -# OpenNebula has dependencies, but these are not included in the package for some reason -# https://github.com/OpenNebula/addon-context-linux/blob/40efc929487b2955e6f32643853a5cdc93c548da/targets.sh#L25 -# It would be useful to see if there is an alternative to OpenNebula without so many dependencies, -# so we can run on FreeBSD base, and avoid breaking OpenNebula when the admin removes a dependency. -env ASSUME_ALWAYS_YES=YES pkg -c /mnt install sudo bash curl base64 ruby open-vm-tools-nox11 gawk virt-what one-context.txz -env ASSUME_ALWAYS_YES=YES pkg -c /mnt clean --all -rm /mnt/one-context.txz +# Set zstd-19 compression, copy all data to the pool, and then set compression to default again +# This will make the base image smaller, at the cost of taking longer to generate, as zstd-19 is slow to write +# Therefore, afterwards we restore compression to default, so written files stay zstd-19, which is fast to read, +# but files written by the user afterwards will be written with the default compression algorihtm. +zfs set compression=zstd-19 $ZPOOL/ROOT/default +umount "$UFSTARGET/dev" "$UFSTARGET/tmp" "$UFSTARGET/var/tmp" +rsync -aH --fileflags --inplace "$UFSTARGET/." "$ZFSTARGET" +sysrc -f "$UFSTARGET/boot/loader.conf" -x zfs_load +printf '%s\t%s\t\t%s\t%s\t%s\t%s\n' /dev/gpt/rootfs / ufs rw,noatime 1 1 >>"$UFSTARGET/etc/fstab" +sync ||: +zfs inherit compression $ZPOOL/ROOT/default trap : EXIT cleanup mkdir -p "$ARCH" -qemu-img convert -f raw -O qcow2 "$disk" "$IMAGE_PATH" -rm "$disk" +qemu-img convert -f raw -O qcow2 "$zfsdisk" "$ARCH/$IMAGE_PATH_ZFS" +qemu-img convert -f raw -O qcow2 "$ufsdisk" "$ARCH/$IMAGE_PATH_UFS" +rm "$zfsdisk" "$ufsdisk" # Filesystem will be enlarged by growfs(7) on next startup -qemu-img resize "$IMAGE_PATH" "$IMAGE_SIZE" +qemu-img resize "$ARCH/$IMAGE_PATH_ZFS" "$IMAGE_SIZE" +qemu-img resize "$ARCH/$IMAGE_PATH_UFS" "$IMAGE_SIZE" diff --git a/opennebula-images/freebsd-zfs-build-opennebula-image.sh b/opennebula-images/freebsd-zfs-build-opennebula-image.sh deleted file mode 100755 index 39992ce..0000000 --- a/opennebula-images/freebsd-zfs-build-opennebula-image.sh +++ /dev/null @@ -1,148 +0,0 @@ -#!/bin/sh - -# This script generates FreeBSD images for OpenNebula, being heavily inspired -# from srht's FreeBSD build image definition. It assumes running on a FreeBSD host. -# ZFS installation as documented by the FreeBSD project -# https://wiki.freebsd.org/RootOnZFS/GPTZFSBoot - -set -e -set -x - -# XXX: Handle command-line arguments? -RELEASE=13.0-RELEASE -ARCH=amd64 -IMAGE_PATH=freebsd-zfs-$RELEASE-$(date -I).img.qcow2 -IMAGE_SIZE=10G - -DIST_BASE="https://download.freebsd.org/ftp/releases/$ARCH/$RELEASE" -ZPOOL=zroot - -ONE_CONTEXT_PKG_URL="https://github.com/OpenNebula/addon-context-linux/releases/download/v6.2.0/one-context-6.2.0_1.txz" - -if zpool list -Ho name $ZPOOL 2>/dev/null; then - echo "The pool $ZPOOL is already imported." >&2 - exit 1 -fi - -cleanup() { - sync || true - umount /mnt/dev || true - zpool export $ZPOOL || true - mdconfig -du md0 || true -} -trap cleanup EXIT - -if [ "$(whoami)" != 'root' ]; then - echo "This script must be run as root." >&2 - exit 1 -fi - -env ASSUME_ALWAYS_YES=YES pkg install -y qemu-tools - -# Allocate and partition/format disk image. -# We use "legacy boot", aka BIOS boot -# Preferably, we'd use EFI boot here, check the FreeBSD wiki link in the header -# to see how to make that change, but make the EFI partition larger -disk=$(mktemp) -truncate -s 6G $disk -mdconfig -a -t vnode -f $disk -u md0 -gpart create -s gpt /dev/md0 -gpart add -t freebsd-boot -l bootfs -b 40 -s 512K md0 -gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 md0 -gpart add -t freebsd-zfs -l zfs0 -b 1M -s 5G md0 -zpool create -O compression=on -o ashift=12 -o altroot=/mnt -m none $ZPOOL md0p2 - -zfs create -o mountpoint=none $ZPOOL/ROOT -# We set zstd-19 so our image will become smaller, at the cost of a longer build time -# At the end, we remove zstd-19 again, but all files already written will remain zstd-19 compressed -zfs create -o mountpoint=/ -o canmount=noauto -o compression=zstd-19 $ZPOOL/ROOT/default -mount -t zfs $ZPOOL/ROOT/default /mnt -zpool set bootfs=$ZPOOL/ROOT/default $ZPOOL - -zfs create -o mountpoint=/tmp -o exec=on -o setuid=off $ZPOOL/tmp -zfs create -o canmount=off -o mountpoint=/usr $ZPOOL/usr -zfs create $ZPOOL/usr/home -zfs create -o exec=off -o setuid=off $ZPOOL/usr/src -zfs create -o mountpoint=/usr/ports -o setuid=off $ZPOOL/usr/ports -zfs create -o canmount=off -o mountpoint=/var $ZPOOL/var -zfs create -o exec=off -o setuid=off $ZPOOL/var/audit -zfs create -o exec=off -o setuid=off $ZPOOL/var/crash -zfs create -o exec=off -o setuid=off $ZPOOL/var/log -zfs create -o atime=on -o exec=off -o setuid=off $ZPOOL/var/mail -zfs create -o exec=on -o setuid=off $ZPOOL/var/tmp - -ln -s /usr/home /mnt/home -chmod 1777 /mnt/var/tmp -chmod 1777 /mnt/tmp - -# Mount allocated image. -mkdir -p /mnt/dev -mount -t devfs devfs /mnt/dev - -# Download and extract base system. -dist_files="kernel.txz base.txz" -dist_dir="/usr/freebsd-dist/$ARCH/$RELEASE" - -mkdir -p "$dist_dir" -for f in $dist_files -do - fetch -m -o "$dist_dir/$f" "$DIST_BASE/$f" - tar -C /mnt -xJf "$dist_dir/$f" -done - -# Configure new system. -printf '# Device\tMountpoint\tFStype\tOptions\tDump\tPass#\n' >/mnt/etc/fstab -touch /mnt/firstboot -sysrc -f /mnt/boot/loader.conf zfs_load=YES autoboot_delay=-1 - -sysrc -f /mnt/etc/rc.conf ntpd_enable=YES sshd_enable=YES growfs_enable=YES hostname=freebsd - -cp /etc/resolv.conf /mnt/etc/resolv.conf -tzsetup -s -C /mnt UTC - -cat >>/mnt/etc/ssh/sshd_config </mnt/usr/local/etc/pkg/repos/FreeBSD.conf - -# freebsd-update is only supported for RELEASE -if [ "${release%-RELEASE}" != "$RELEASE" ] -then - env PAGER=true /usr/sbin/freebsd-update \ - -b /mnt \ - --currently-running "$RELEASE" \ - --not-running-from-cron -F \ - fetch install - rm -rf /mnt/var/db/freebsd-update/* -fi - -env ASSUME_ALWAYS_YES=YES pkg -c /mnt bootstrap -f - -fetch -m -o /mnt/one-context.txz "$ONE_CONTEXT_PKG_URL" -# OpenNebula has dependencies, but these are not included in the package for some reason -# https://github.com/OpenNebula/addon-context-linux/blob/40efc929487b2955e6f32643853a5cdc93c548da/targets.sh#L25 -# It would be useful to see if there is an alternative to OpenNebula without so many dependencies, -# so we can run on FreeBSD base, and avoid breaking OpenNebula when the admin removes a dependency. -env ASSUME_ALWAYS_YES=YES pkg -c /mnt install sudo bash curl base64 ruby open-vm-tools-nox11 gawk virt-what one-context.txz -env ASSUME_ALWAYS_YES=YES pkg -c /mnt clean --all -rm /mnt/one-context.txz - -# Remove zstd-19 again, as it would be too slow for daily use. -# But all files that were already writtne will remain zstd-19 compressed. -# zstd-19 is slow to compress but fast to read. -zfs inherit compression $ZPOOL/ROOT/default - -trap : EXIT -cleanup - -mkdir -p "$ARCH" -qemu-img convert -f raw -O qcow2 "$disk" "$IMAGE_PATH" -rm "$disk" - -# Filesystem will be enlarged by growfs(7) on next startup -qemu-img resize "$IMAGE_PATH" "$IMAGE_SIZE"