From 7c674a11ca49df28f78f49a876660891ad7b4355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sp=C3=B6hel?= Date: Thu, 24 Aug 2023 16:35:18 +0200 Subject: basic cnt build for vms (debconf only) --- libexec/container/build | 7 +- share/build-scripts/debconf | 170 ++++++++++++++++- share/build-scripts/debconf.d/0003-debconf | 209 +++++++++++++++++++++ .../build-scripts/debconf.d/0003-debconf.templates | 82 ++++++++ share/config/container.conf.in | 14 ++ share/doc/vms.txt | 16 ++ 6 files changed, 491 insertions(+), 7 deletions(-) create mode 100644 share/doc/vms.txt diff --git a/libexec/container/build b/libexec/container/build index 2c29730..efb42f3 100755 --- a/libexec/container/build +++ b/libexec/container/build @@ -32,7 +32,7 @@ CONFIG_TEMPLATE="/usr/share/${SOFTWARE}/config/container.conf.in" Parameters () { - GETOPT_LONGOPTIONS="name:,cnt.auto:,cnt.container-server:,cnt.overlay:,cnt.overlay-options:,cnt.start:,bind:,bind-ro:,capability:,drop-capability:,script:,verbose," + GETOPT_LONGOPTIONS="name:,cnt.auto:,cnt.container-server:,cnt.overlay:,cnt.overlay-options:,cnt.start:,bind:,bind-ro:,capability:,drop-capability:,script:,boot-method:,verbose," GETOPT_OPTIONS="n:,b:,c:,d:,s:,v," PARAMETERS="$(getopt --longoptions ${GETOPT_LONGOPTIONS} --name=${COMMAND} --options ${GETOPT_OPTIONS} --shell sh -- ${@})" @@ -108,6 +108,11 @@ Parameters () shift 1 ;; + --boot-method) + BOOT_METHOD="${2}" + shift 2 + ;; + --) shift 1 break diff --git a/share/build-scripts/debconf b/share/build-scripts/debconf index 900242d..8307695 100755 --- a/share/build-scripts/debconf +++ b/share/build-scripts/debconf @@ -31,11 +31,12 @@ CACHE="/var/cache/${PROGRAM}/build-$(basename ${SCRIPT})" CONFIG="/etc/${SOFTWARE}/config" HOOKS="/etc/${SOFTWARE}/hooks" MACHINES="/var/lib/machines" +VMS="/srv/container/vms" Parameters () { - GETOPT_LONGOPTIONS="bind:,bind-ro:,script:,name:,preseed-file:" - GETOPT_OPTIONS="b:,s:,n:,p:" + GETOPT_LONGOPTIONS="bind:,bind-ro:,boot-method:,script:,name:,preseed-file:,vm" + GETOPT_OPTIONS="b:,s:,n:,p:,v:" PARAMETERS="$(getopt --longoptions ${GETOPT_LONGOPTIONS} --name=${SCRIPT} --options ${GETOPT_OPTIONS} --shell sh -- ${@})" @@ -60,6 +61,11 @@ Parameters () shift 2 ;; + --boot-method) + BOOT_METHOD="${2}" + shift 2 + ;; + --cnt.auto) # ignore shift 2 @@ -85,6 +91,11 @@ Parameters () shift 2 ;; + --vm) + VM="TRUE" + shift 1 + ;; + --) shift 1 break @@ -100,7 +111,7 @@ Parameters () Usage () { - echo "Usage: container build -n|--name NAME -s|--script ${SCRIPT} -- [-p|--preseed-file FILE]" >&2 + echo "Usage: container build -n|--name NAME -s|--script ${SCRIPT} [--boot-method systemd-nswawn|qemu] -- [-p|--preseed-file FILE]" >&2 exit 1 } @@ -251,9 +262,20 @@ Umount () fi # Unmounting pseudo-filesystems + # FIXME this should not be necessary + umount -f "${DIRECTORY}/dev" > /dev/null 2>&1 || true umount -f "${DIRECTORY}/dev/pts" > /dev/null 2>&1 || true umount -f "${DIRECTORY}/proc" > /dev/null 2>&1 || true umount -f "${DIRECTORY}/sys" > /dev/null 2>&1 || true + + # Unmounting disk images + if [ "${BOOT_METHOD}" = "qemu" ] + then + umount -f "${DIRECTORY}/boot/efi" > /dev/null 2>&1 || true + umount -f "${DIRECTORY}" > /dev/null 2>&1 || true + rmdir "${MACHINES}/${NAME}" + kpartx -d "${VMS}/${NAME}/root.img" + fi } Chroot () @@ -368,7 +390,8 @@ Bootstrap () DIRECTORY="${1}" EXCLUDE="ifupdown" - INCLUDE="dbus" + #FIXME amd64 hardcoded + INCLUDE="dbus,linux-image-amd64,grub-efi-amd64" # apt repositories INCLUDE="${INCLUDE},gnupg" @@ -1101,6 +1124,60 @@ EOF done } +Configure_vm () +{ + DIRECTORY="${1}" + + # FIXME duplicate definition + EFI_PARTITION="p1" + SYSTEM_PARTITION="p2" + EFI_UUID="$(lsblk --output UUID --noheadings /dev/mapper/loop0${EFI_PARTITION})" + ROOT_UUID="$(lsblk --output UUID --noheadings /dev/mapper/loop0${SYSTEM_PARTITION})" + echo "UUID=${ROOT_UUID} / ext4 discard,noatime,errors=remount-ro 0 1" >> ${DIRECTORY}/etc/fstab + echo "UUID=${EFI_UUID} /boot/efi vfat umask=0077 0 1" >> ${DIRECTORY}/etc/fstab + + mkdir -p ${DIRECTORY}/boot/efi/EFI/progress-linux + cp ${DIRECTORY}/usr/lib/grub/x86_64-efi/monolithic/grubx64.efi ${DIRECTORY}/boot/efi/EFI/progress-linux/ + +cat > ${DIRECTORY}/boot/efi/EFI/progress-linux/grub.cfg << EOF +search.fs_uuid ${ROOT_UUID} root +set prefix=(\$root)'/boot/grub' +configfile \$prefix/grub.cfg +EOF + +cat >> ${DIRECTORY}/etc/initramfs-tools/modules << EOF + +# enable virtio +virtio_pci +virtio_blk +virtio_net +EOF + + Chroot ${DIRECTORY} update-initramfs -u + + mount -o bind /dev ${DIRECTORY}/dev + Chroot ${DIRECTORY} update-grub + + # FIXME workaround for grub not being installed as EFI/boot/bootx86.efi + mkdir "${DIRECTORY}/boot/efi/EFI/boot" + echo 'fs0:\EFI\progress-linux\grubx64.efi' > "${DIRECTORY}/boot/efi/EFI/boot/startup.nsh" + + sed -i \ + -e "s|@BOOT_METHOD@|${BOOT_METHOD}|g" \ + -e "s|@CPU@|${CPU}|g" \ + -e "s|@MEMORY@|${MEMORY}|g" \ + -e "s|@DISPLAY@|${DISPLAY}|g" \ + -e "s|@SERIAL@|${SERIAL}|g" \ + -e "s|@MONITOR@|${MONITOR}|g" \ + -e "s|@FIRMWARE@|${FIRMWARE}|g" \ + -e "s|@DRIVE@|${DRIVE}|g" \ + -e "s|@NETDEV@|${NETDEV}|g" \ + -e "s|@QEMU_RAW@|${QEMU_RAW}|g" \ + "${CONFIG}/${NAME}.conf" + +} + + Commands () { DIRECTORY="${1}" @@ -1117,6 +1194,7 @@ Commands () -e "s|^bind=.*|bind=${BIND}|g" \ -e "s|^bind-ro=.*|bind-ro=${BIND_RO}|g" \ -e "s|^network-veth-extra=.*|network-veth-extra=${HOST_INTERFACE_NAME}:eno1|g" \ + -e "s|@PRIMARY_TAP@|${HOST_INTERFACE_NAME}|g" \ "${CONFIG}/${NAME}.conf" if [ "${NETWORK_NUMBER}" -ge 2 ] @@ -1179,6 +1257,67 @@ Commands () esac } +Create_vm_disk () +{ + mkdir -p "${VMS}/${NAME}" + + # FIXME drive-image file size as arg or preseed + DRIVE_SIZE=12000 + + # FIXME image name + dd if=/dev/zero of="${VMS}/${NAME}/root.img" bs=1024k count=0 seek="${DRIVE_SIZE}" + parted "${VMS}/${NAME}/root.img" mklabel gpt + + + # FIXME only for root image + case "${FIRMWARE}" in + legacy) + # FIXME number partitions and size scrip and everything + parted -a optimal "${VMS}/${NAME}/root.img" mkpart BIOS-BOOT 1MB 2MB + parted "${VMS}/${NAME}/root.img" set 1 bios_grub on + parted -a optimal "${VMS}/${NAME}/root.img" mkpart SYSTEM 2MB 100% + SYSTEM_PARTITION="p2" + ;; + + efi) + parted -a optimal "${VMS}/${NAME}/root.img" mkpart EFI fat32 1M 1000M + parted "${VMS}/${NAME}/root.img" set 1 esp on + parted -a optimal "${VMS}/${NAME}/root.img" mkpart SYSTEM 1000MB 100% + EFI_PARTITION="p1" + SYSTEM_PARTITION="p2" + + # efi bios + cp /usr/share/qemu/OVMF.fd "${VMS}/${NAME}/firmware.fd" + ;; + + *) + echo "Error, unrecognized firware." >&2 + exit 1 + esac + + kpartx -av "${VMS}/${NAME}/root.img" + # FIXME loop number hardcoded + mkfs.ext4 "/dev/mapper/loop0${SYSTEM_PARTITION}" + + if [ ! -z "${EFI_PARTITION}" ] + then + mkfs.vfat -F 32 "/dev/mapper/loop0${EFI_PARTITION}" + fi + + # FIXME swap, more discs +} + +Mount_vm_disk () +{ + # FIXME probably not necessary + mkdir -p "${MACHINES}/${NAME}" + + # FIXME partition number hardcoded + mount "/dev/mapper/loop0${SYSTEM_PARTITION}" "${MACHINES}/${NAME}" + mkdir -p "${MACHINES}/${NAME}/boot/efi" + mount "/dev/mapper/loop0${EFI_PARTITION}" "${MACHINES}/${NAME}/boot/efi" +} + # Trap function trap 'Umount' EXIT HUP INT QUIT TERM @@ -1218,6 +1357,13 @@ else INSTALLER="image" fi +case "${BOOT_METHOD}" in + qemu) + Create_vm_disk + Mount_vm_disk + ;; +esac + case "${INSTALLER}" in bootstrap) ## Dependencies @@ -1246,8 +1392,11 @@ case "${INSTALLER}" in Cleanup_system "${CACHE}/${DISTRIBUTION}_${ARCHITECTURE}" ## Specific parts - mkdir -p "${MACHINES}" - cp -a "${CACHE}/${DISTRIBUTION}_${ARCHITECTURE}" "${MACHINES}/${NAME}" + + # FIXME is there a better way to do this? + mkdir -p "${MACHINES}/${NAME}" + cp -a "${CACHE}/${DISTRIBUTION}_${ARCHITECTURE}/"* "${MACHINES}/${NAME}/" + ;; image) @@ -1300,6 +1449,15 @@ Mount Configure_system "${MACHINES}/${NAME}" Configure_network "${MACHINES}/${NAME}" Configure_systemd_networkd "${MACHINES}/${NAME}" + +case "${BOOT_METHOD}" in + qemu) + echo DEBUG: Configure_vm start + Configure_vm "${MACHINES}/${NAME}" + echo DEBUG: Configure_vm end + ;; +esac + Cleanup_system "${MACHINES}/${NAME}" Commands "${MACHINES}/${NAME}" diff --git a/share/build-scripts/debconf.d/0003-debconf b/share/build-scripts/debconf.d/0003-debconf index e12e25e..76da4c2 100755 --- a/share/build-scripts/debconf.d/0003-debconf +++ b/share/build-scripts/debconf.d/0003-debconf @@ -1340,6 +1340,195 @@ Internal_options () echo "CNT_OVERLAY_OPTIONS=\"${CNT_OVERLAY_OPTIONS}\"" >> "${DEBCONF_TMPDIR}/debconf.default" } +Cpu () +{ + db_get container/cpu + CPU="${RET}" # select + + if [ -z "${CPU}" ] + then + CPU="${RET}" # string (w/o empty) + + case "${CPU}" in + debconf) + CPU="host" + ;; + esac + fi + + echo "CPU=\"${CPU}\"" >> "${DEBCONF_TMPDIR}/debconf.default" + export CPU +} + +Memory () +{ + db_get container/memory + MEMORY="${RET}" # select + + if [ -z "${MEMORY}" ] + then + MEMORY="${RET}" # string (w/o empty) + + case "${MEMORY}" in + debconf) + MEMORY="2G" + ;; + esac + fi + + echo "MEMORY=\"${MEMORY}\"" >> "${DEBCONF_TMPDIR}/debconf.default" + export MEMORY +} + +Display () +{ + db_get container/display + DISPLAY="${RET}" # select + + if [ -z "${DISPLAY}" ] + then + DISPLAY="${RET}" # string (w/o empty) + + case "${DISPLAY}" in + debconf) + DISPLAY="2G" + ;; + esac + fi + + echo "DISPLAY=\"${DISPLAY}\"" >> "${DEBCONF_TMPDIR}/debconf.default" + export DISPLAY +} + +Serial () +{ + db_get container/serial + SERIAL="${RET}" # select + + if [ -z "${SERIAL}" ] + then + SERIAL="${RET}" # string (w/o empty) + + case "${SERIAL}" in + debconf) + SERIAL="host" + ;; + esac + fi + + echo "SERIAL=\"${SERIAL}\"" >> "${DEBCONF_TMPDIR}/debconf.default" + export SERIAL +} + +Monitor () +{ + db_get container/monitor + MONITOR="${RET}" # select + + if [ -z "${MONITOR}" ] + then + MONITOR="${RET}" # string (w/o empty) + + case "${MONITOR}" in + debconf) + MONITOR="host" + ;; + esac + fi + + echo "MONITOR=\"${MONITOR}\"" >> "${DEBCONF_TMPDIR}/debconf.default" + export MONITOR +} + +Firmware () +{ + db_get container/firmware + FIRMWARE="${RET}" # select + + if [ -z "${FIRMWARE}" ] + then + FIRMWARE="${RET}" # string (w/o empty) + + case "${FIRMWARE}" in + debconf) + FIRMWARE="host" + ;; + esac + fi + + echo "FIRMWARE=\"${FIRMWARE}\"" >> "${DEBCONF_TMPDIR}/debconf.default" + export FIRMWARE +} + +Drive () +{ + db_get container/drive + DRIVE="${RET}" # select + + if [ -z "${DRIVE}" ] + then + DRIVE="${RET}" # string (w/o empty) + + case "${DRIVE}" in + debconf) + DRIVE="host" + ;; + esac + fi + + echo "DRIVE=\"${DRIVE}\"" >> "${DEBCONF_TMPDIR}/debconf.default" + export DRIVE +} + +Netdev () +{ + db_get container/netdev + NETDEV="${RET}" # string (w/ empty) + + echo "NETDEV=\"${NETDEV}\"" >> "${DEBCONF_TMPDIR}/debconf.default" + export NETDEV +} + +Qemu_raw () +{ + db_get container/qemu-raw + QEMU_RAW="${RET}" # select + + if [ -z "${QEMU_RAW}" ] + then + QEMU_RAW="${RET}" # string (w/o empty) + + case "${QEMU_RAW}" in + debconf) + QEMU_RAW="host" + ;; + esac + fi + + echo "QEMU_RAW=\"${QEMU_RAW}\"" >> "${DEBCONF_TMPDIR}/debconf.default" + export QEMU_RAW +} + +Boot_method () +{ + db_get container/boot-method + BOOT_METHOD="${RET}" # select + + if [ -z "${BOOT_METHOD}" ] + then + BOOT_METHOD="${RET}" # string (w/o empty) + + case "${BOOT_METHOD}" in + debconf) + BOOT_METHOD="systemd-nspawn" + ;; + esac + fi + + echo "BOOT_METHOD=\"${BOOT_METHOD}\"" >> "${DEBCONF_TMPDIR}/debconf.default" + export BOOT_METHOD +} + Mode Images @@ -1368,4 +1557,24 @@ Root_password Internal_options +Cpu + +Memory + +Display + +Serial + +Monitor + +Firmware + +Drive + +Netdev + +Qemu_raw + +Boot_method + db_stop diff --git a/share/build-scripts/debconf.d/0003-debconf.templates b/share/build-scripts/debconf.d/0003-debconf.templates index 551033a..5d83df3 100644 --- a/share/build-scripts/debconf.d/0003-debconf.templates +++ b/share/build-scripts/debconf.d/0003-debconf.templates @@ -274,3 +274,85 @@ Description: Nameserver Resolver Options? See resolv.conf(5) for more information about the 'options' option. . This defaults to empty. + +Template: container/cpu +Type: string +Default: +Description: Cpu + VM CPU should be emulated. + . + Use 'host' for kvm. + . + This defaults to empty. + +Template: container/memory +Type: string +Default: +Description: Memory + Memory options for the VM. + . + This defaults to empty. + +Template: container/display +Type: string +Default: +Description: Display + Display options for the VM. + . + This defaults to empty. + +Template: container/serial +Type: string +Default: +Description: Serial + Serial options for the VM. + . + This defaults to empty. + +Template: container/monitor +Type: string +Default: +Description: Monitor + Monitor options for the VM. + . + This defaults to empty. + +Template: container/firmware +Type: string +Default: +Description: Firmware + Firmware options for the VM. + . + This defaults to empty. + +Template: container/drive +Type: string +Default: +Description: Drive + Drive options for the VM. + . + This defaults to empty. + +Template: container/netdev +Type: string +Default: +Description: Netdev + Netdev options for the VM. + . + This defaults to empty. + +Template: container/qemu-raw +Type: string +Default: +Description: Qemu-raw + Raw options for the VM. + . + This defaults to empty. + +Template: container/boot-method +Type: string +Default: +Description: Boot-method + Either 'efi' or 'legacy'. + . + This defaults to empty. diff --git a/share/config/container.conf.in b/share/config/container.conf.in index d3f9a48..9a0c9b2 100644 --- a/share/config/container.conf.in +++ b/share/config/container.conf.in @@ -10,6 +10,7 @@ cnt.start=@CNT_START@ bind=@BIND@ bind-ro=@BIND_RO@ boot=@BOOT@ +boot-method=@BOOT_METHOD@ capability=@CAPABILITY@ directory=@DIRECTORY@ drop-capability=@DROP_CAPABILITY@ @@ -28,3 +29,16 @@ CPUQuota= CPUShares= MemoryLimit= TasksMax= + +[vm] +vm.memory=@MEMORY@ +vm.cpu=@CPU@ +vm.display=@DISPLAY@ +vm.serial=@SERIAL@ +vm.mon=@MONITOR@ +vm.firmware=@FIRMWARE@ + +vm.drive=@DRIVE@ +vm.netdev=@NETDEV@ + +vm.raw=@QEMU_RAW@ diff --git a/share/doc/vms.txt b/share/doc/vms.txt new file mode 100644 index 0000000..453ce23 --- /dev/null +++ b/share/doc/vms.txt @@ -0,0 +1,16 @@ +Manage Virtual Machines (VMs) +============================= + +Status: + +- only debconf is supported + +HOWTO: + +to generate a vm image, provide the --vm option: + + cnt build -n test --vm + +dependencies: + + apt install qemu-system ovmf -- cgit v1.2.3