commit:     48a56d53fa7b00ac319a25315bd309914f6d8da4
Author:     Andreas K. Hüttel <dilfridge <AT> gentoo <DOT> org>
AuthorDate: Sun Oct 13 14:42:49 2024 +0000
Commit:     Andreas K. Hüttel <dilfridge <AT> gentoo <DOT> org>
CommitDate: Sun Oct 13 20:30:49 2024 +0000
URL:        https://gitweb.gentoo.org/proj/catalyst.git/commit/?id=48a56d53

Script to create a bootable qcow2 image

Signed-off-by: Andreas K. Hüttel <dilfridge <AT> gentoo.org>

 targets/support/create-qcow2.sh | 188 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 188 insertions(+)

diff --git a/targets/support/create-qcow2.sh b/targets/support/create-qcow2.sh
new file mode 100755
index 00000000..0073a25c
--- /dev/null
+++ b/targets/support/create-qcow2.sh
@@ -0,0 +1,188 @@
+#!/bin/bash
+
+source ${clst_shdir}/support/functions.sh
+
+## START RUNSCRIPT
+
+# Supported host architectures: all that do UEFI boot and support the tools
+# Script parameters:
+#  - ${1}  output qcow2 file
+
+#
+# Configuration parameters:
+# All sizes are in forms as understood by parted: use MiB, GiB, ... or M, G, 
...
+#  - clst_qcow2_size      (internal) size of the qcow2 image (default 20GiB)
+#  - clst_qcow2_efisize   size of the EFI boot partition (default 512MiB)
+#  - clst_qcow2_roottype  type of the root partition (default xfs)
+#
+: "${clst_qcow2_size:=20GiB}"
+: "${clst_qcow2_efisize:=512MiB}"
+: "${clst_qcow2_roottype:=xfs}"
+
+#
+# We only support one set of tools, based on
+#  - mkfs.vfat    ( sys-fs/dosfstools , for the EFI partition )
+#  - mkfs.xfs     ( sys-fs/xfsprogs , this might actually be configurable )
+#  - parted       ( sys-block/parted , for partitioning )
+#  - qemu-nbd     ( app-emulation/qemu , for accessing a qcow2 image file as 
device )
+#  - qemu-img     ( app-emulation/qemu , for creating a qcow2 image file )
+#
+# Let's assume these are deps of catalyst and thus present.
+#
+
+mymountpoint="${1}.tmp.mnt"
+myqcow2="${1}"
+
+# TODO: find next free device
+modprobe -q nbd
+mydevice=/dev/nbd0
+
+# This script requires slightly more stringent cleanup in case of errors
+# from the moment on when the nbd was set up...
+qcow2die() {
+       echo "Something went wrong. Cleaning up..."
+
+       # here we just ignore errors
+       umount -R "${mymountpoint}/proc"
+       umount -R "${mymountpoint}/sys"
+       umount -R "${mymountpoint}/dev"
+       umount -R "${mymountpoint}/run"
+
+       umount "${mydevice}p1"
+       umount "${mydevice}p2"
+       qemu-nbd -d "${mydevice}"
+
+       die "$@"
+}
+
+# We need a means to execute a script inside the qcow with filesystems mounted
+# Which means reproducing half of catalyst here.
+exec_in_qcow2() {
+       local file_name=$(basename ${1})
+
+       # prepare qcow2 for chrooting
+       mount --types proc /proc "${mymountpoint}/proc"
+       mount --rbind /sys "${mymountpoint}/sys"
+       mount --make-rslave "${mymountpoint}/sys"
+       mount --rbind /dev "${mymountpoint}/dev"
+       mount --make-rslave "${mymountpoint}/dev"
+       mount --bind /run "${mymountpoint}/run"
+       mount --make-slave "${mymountpoint}/run"
+
+       # copy_to_chroot ${1}
+       cp -pPR "${1}" "${mymountpoint}/tmp" || qcow2die
+        # copy_to_chroot ${clst_shdir}/support/chroot-functions.sh
+        cp -pPR "${clst_shdir}/support/chroot-functions.sh" 
"${mymountpoint}/tmp" || qcow2die
+
+        # Ensure the file has the executable bit set
+        chmod +x "${mymountpoint}/tmp/${file_name}" || qcow2die
+
+        echo "Running ${file_name} in qcow2:"
+        echo "    ${clst_CHROOT} ${mymountpoint} /tmp/${file_name}"
+        ${clst_CHROOT} "${mymountpoint}" "/tmp/${file_name}" || qcow2die
+
+        rm -f "${mymountpoint}/tmp/${file_name}" || qcow2die
+        rm -f "${mymountpoint}/tmp/chroot-functions.sh" || qcow2die
+
+       # cleanup qcow2 dir
+       umount -R "${mymountpoint}/proc" || qcow2die
+       umount -R "${mymountpoint}/sys" || qcow2die
+       umount -R "${mymountpoint}/dev" || qcow2die
+       umount -R "${mymountpoint}/run" || qcow2die
+}
+
+
+echo "Creating a new qcow2 disk image file ${myqcow2}.tmp.qcow2 with size 
${clst_qcow2_size/%iB/}"
+qemu-img create -f qcow2 "${myqcow2}.tmp.qcow2" ${clst_qcow2_size/%iB/} || die 
"Cannot create qcow2 file"
+
+echo "Connecting the qcow2 file to network block device ${mydevice}"
+qemu-nbd -c ${mydevice} -f qcow2 "${myqcow2}.tmp.qcow2" || die "Cannot connect 
qcow2 file to nbd0"
+
+echo "Creating a GPT disklabel"
+parted -s ${mydevice} mklabel gpt || qcow2die "Cannot create disklabel"
+
+echo "Creating an EFI boot partition"
+parted -s ${mydevice} -- mkpart gentooefi fat32 1M ${clst_qcow2_efisize} || 
qcow2die "Cannot create EFI partition"
+# mark it as EFI boot partition
+parted -s ${mydevice} -- type 1 C12A7328-F81F-11D2-BA4B-00A0C93EC93B || 
qcow2die "Cannot set EFI partition UUID"
+# note down name
+mypartefi=${mydevice}p1
+
+echo "Creating the root partition"
+parted -s ${mydevice} -- mkpart gentooroot ${clst_qcow2_roottype} 
${clst_qcow2_efisize}GiB -1M || qcow2die "Cannot create root partition"
+# mark it as generic linux filesystem partition
+parted -s ${mydevice} -- type 2 0FC63DAF-8483-4772-8E79-3D69D8477DE4 || 
qcow2die "Cannot set root partition UUID"
+# note down name
+mypartroot=${mydevice}p2
+
+echo "Re-reading the partition table"
+partprobe ${mydevice} || qcow2die "Probing partition table failed"
+
+echo "Printing the partition table"
+parted -s ${mydevice} -- print || qcow2die "Printing the partition table 
failed"
+
+echo "Making a vfat filesystem in p1"
+mkfs.fat -v -F 32 -n gentooefi ${mypartefi} || qcow2die "Formatting EFI 
partition failed"
+
+echo "Making an xfs filesystem in p2"
+mkfs.xfs -L gentooroot ${mypartroot} || qcow2die "Formatting root partition 
failed"
+
+echo "Printing blkid output"
+blkid ${mydevice}* || qcow2die "blkid failed"
+
+echo "Mounting things at ${mymountpoint}"
+mkdir -p "${mymountpoint}" || qcow2die "Could not create root mount point"
+mount ${mypartroot} "${mymountpoint}" || qcow2die "Could not mount root 
partition"
+mkdir -p "${mymountpoint}"/boot || qcow2die "Could not create boot mount point"
+mount ${mypartefi} "${mymountpoint}/boot" || qcow2die "Could not mount boot 
partition"
+
+# copy contents in; the source is the stage dir and not any "iso content"
+echo "Copying files into the mounted directories from ${clst_stage_path}"
+cp -a "${clst_stage_path}"/* "${mymountpoint}/" || qcow2die "Could not copy 
content into mounted image"
+
+echo "Setting machine-id to empty"
+# We are already running systemd-firstboot in a previous step, so we don't 
want to run it again.
+# The documented behaviour for an empty machine-id is that systemd generates a 
new one and commits
+# it on first boot, but otherwise treats the system as already initialized.
+rm -f "${mymountpoint}/etc/machine-id"
+touch "${mymountpoint}/etc/machine-id" || qcow2die "Could not set machine-id 
to empty"
+
+# now we can chroot in and install grub
+exec_in_qcow2 "${clst_shdir}/support/qcow2-grub-install.sh"
+
+echo "Generating /etc/fstab"
+cat > "${mymountpoint}/etc/fstab" <<END
+# /etc/fstab: static file system information.
+#
+# See the manpage fstab(5) for more information.
+#
+# <fs>                  <mountpoint>    <type>          <opts>          
<dump/pass>
+
+LABEL=gentooroot            /               xfs              noatime,rw   0 1
+LABEL=gentooefi             /boot           vfat             defaults     1 2
+
+END
+
+echo "Creating a CONTENTS file ${myqcow2}.CONTENTS"
+pushd "${mymountpoint}/" &> /dev/null || qcow2die "Could not cd into 
mountpoint"
+ls -laR > "${myqcow2}.CONTENTS"       || qcow2die "Could not create CONTENTS 
file"
+popd &> /dev/null                     || qcow2die "Could not cd out of 
mountpoint"
+
+echo "Compressing the CONTENTS file"
+gzip "${myqcow2}.CONTENTS"      || qcow2die "Could not compress the CONTENTS 
file"
+
+echo "Unmounting things"
+umount "${mymountpoint}/boot" || qcow2die "Could not unmount boot partition"
+umount "${mymountpoint}" || qcow2die "Could not unmount root partition"
+
+echo "Disconnecting ${mydevice}"
+qemu-nbd -d ${mydevice} || qcow2die "Could not disconnect ${mydevice}"
+
+echo "Rewriting the qcow2 file with stream compression to ${myqcow2}"
+qemu-img convert -c -O qcow2 "${myqcow2}.tmp.qcow2" "${myqcow2}" || qcow2die 
"Could not compress QCOW2 file"
+
+echo "Cleaning up"
+rm "${myqcow2}.tmp.qcow2" || qcow2die "Could not delete uncompressed QCOW2 
file"
+rmdir "${mymountpoint}" || qcow2die "Could not remove mountpoint"
+
+# Finished...

Reply via email to