diff options
Diffstat (limited to 'bin/debvm-create')
-rwxr-xr-x | bin/debvm-create | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/bin/debvm-create b/bin/debvm-create new file mode 100755 index 0000000..c554165 --- /dev/null +++ b/bin/debvm-create @@ -0,0 +1,300 @@ +#!/bin/sh +# Copyright 2022 Helmut Grohne <helmut@subdivi.de> +# SPDX-License-Identifier: MIT + +# shellcheck disable=SC2016 # Intentional quoting technique + +: <<'POD2MAN' +=head1 NAME + +debvm-create - Create a VM image for various Debian releases and architectures + +=head1 SYNOPSIS + +B<debvm-create> [B<-a> I<architecture>] [B<-h> I<hostname>] [B<-k> F<sshkey>] [B<-o> F<output>] [B<-r> I<release>] [B<-s> <task>] [B<-z> I<size>] [B<--> I<mmdebstrap options>] + +=head1 DESCRIPTION + +B<debvm-create> is essentially a thin wrapper around B<mmdebstrap> for creating a raw ext4 filesystem image for booting with B<debvm-run>. +The purpose of these images primarily is testing the different releases and architectures without access to a physical machine of that architecture. +Beyond essential packages, the image will contain B<apt>, an init system and a suitable kernel package. +Notably absent is a bootloader and a partition table. +In order to boot such an image, one is supposed to extract the kernel and initrd from the image and pass it to a suitable bootloader. +No user account is created and root can login without specifying a password. + +=head1 OPTIONS + +=over 8 + +=item B<-a> I<architecture>, B<--architecture>=I<architecture> + +Specify a Debian architecture name. +By default, the native architecture is being used. +A suitable kernel image is automatically selected and installed into the image. + +=item B<-h> I<hostname>, B<--hostname>=I<hostname> + +Set the hostname of the virtual machine. +By default, the hostname is B<testvm>. + +=item B<-k> F<sshkey>, B<--sshkey>=F<sshkey> + +Install the given ssh public key file into the virtual machine image for the root user. +This option also causes the ssh server to be installed. +By default, no key or server is installed. +To connect to the vm, pass a port number to B<debvm-run> with the B<-s> option. + +=item B<-o> F<output>, B<--output>=F<output> + +Specify the file name of the resulting virtual machine image. +By default, it is written to F<rootfs.ext4>. + +=item B<-r> I<release>, B<--release>=I<release> + +Use the given Debian release. +By default, B<unstable> is being used. + +=item B<-s> I<task>, B<--skip>=I<task> + +Skip a particular task or feature. +The option may be specified multiple times or list multiple tasks to be skipped by separating them with a comma. +By default, no tasks are skipped. +The following tasks may be skipped. + +=over 4 + +=item B<autologin> + +Skips adding a the customize-autologin.sh to B<mmdebstrap> that configures +automatic root login on a serial console and also parses the C<TERM> kernel +cmdline and passes it as C<TERM> to B<agetty>. + +=item B<kernel> + +skips installing a linux kernel image. +This can be useful to install a kernel without a package. +If a kernel is installed via B<mmdebstrap> option C<--include>, automtatic kernel installation is automatically skipped. + +=item B<packagelists> + +reduces the package lists inside the image. +The B<available> database for B<dpkg> is not created. +The package lists used by B<apt> are deleted. +This generally produces a smaller image, but you need to run B<apt update> before installing packages and B<dpkg --set-selections> does not work. + +=item B<systemdnetwork> + +skips installing B<libnss-resolve> as well as automatic network configuration via B<systemd-networkd>. + +=item B<usrmerge> + +By default B<debvm> adds a hook to enable merged-/usr without the B<usrmerge> package given a sufficiently recent Debian release. +Without the hook, dependencies will pull the B<usrmerge> package as needed, which may result in a larger installation. + +=back + +=item B<-z> I<size>, B<--size>=I<size> + +Specify the minimum image size as an integer and optional unit (example: 10K is 10*1024). +Units are K,M,G,T,P,E,Z,Y (powers of 1024) or KB,MB,... (powers of 1000). +The resulting image will be grown as a sparse file to this size if necessary. +The default is 1 GB. + +=item B<--> I<mmdebstrap options> + +All options beyond a double dash are passed to B<mmdebstrap> after the suite and target specification. +This can be used to provide additional hooks for image customization. +You can also request additional packages to be installed into the image using B<mmdebstrap>'s B<--include> option. +Any positional arguments passed here will be treated as mirror specifications by B<mmdebstrap>. + +=back + +=head1 EXAMPLES + +In order to create images for Debian ports architectures, you can pass two options to mmdebstrap: + + debvm-create ... -- http://deb.debian.org/debian-ports --keyring=/usr/share/keyrings/debian-ports-archive-keyring.gpg + +=head1 SEE ALSO + + debvm-run(1) mmdebstrap(1) + +=cut +POD2MAN + +set -u + +ARCHITECTURE=$(dpkg --print-architecture) +IMAGE=rootfs.ext4 +SIZE=1G +SKIP=, +SSHKEY= +SUITE=unstable +VMNAME=testvm + +SHARE_DIR="${0%/*}/../share" + +nth_arg() { + shift "$1" + printf "%s" "$1" +} + +die() { + echo "$*" 1>&2 + exit 1 +} +usage() { + die "usage: $0 [-a architecture] [-h hostname] [-k sshkey] [-o output] [-r release] [-s task] [-z size] [-- mmdebstrap options]" +} +usage_error() { + echo "error: $*" 1>&2 + usage +} + +opt_architecture() { + ARCHITECTURE=$1 +} +opt_hostname() { + VMNAME=$1 +} +opt_skip() { + SKIP="$SKIP$1," +} +opt_sshkey() { + SSHKEY=$1 +} +opt_output() { + IMAGE=$1 + test "${IMAGE#-}" = "$IMAGE" || IMAGE="./$IMAGE" +} +opt_release() { + SUITE=$1 +} +opt_size() { + SIZE=$1 +} + +while getopts :a:h:k:o:r:s:z:-: OPTCHAR; do + case "$OPTCHAR" in + a) opt_architecture "$OPTARG" ;; + h) opt_hostname "$OPTARG" ;; + k) opt_sshkey "$OPTARG" ;; + o) opt_output "$OPTARG" ;; + r) opt_release "$OPTARG" ;; + s) opt_skip "$OPTARG" ;; + z) opt_size "$OPTARG" ;; + -) + case "$OPTARG" in + help) + usage + ;; + architecture|hostname|output|release|size|skip|sshkey) + test "$OPTIND" -gt "$#" && usage_error "missing argument for --$OPTARG" + "opt_$OPTARG" "$(nth_arg "$OPTIND" "$@")" + OPTIND=$((OPTIND+1)) + ;; + architecture=*|hostname=*|output=*|release=*|size=*|skip=*|sshkey=*) + "opt_${OPTARG%%=*}" "${OPTARG#*=}" + ;; + *) + usage_error "unrecognized option --$OPTARG" + ;; + esac + ;; + :) + usage_error "missing argument for -$OPTARG" + ;; + '?') + usage_error "unrecognized option -$OPTARG" + ;; + *) + die "internal error while parsing command options, please report a bug" + ;; + esac +done +shift "$((OPTIND - 1))" + +if test -n "$SSHKEY" && ! test -f "$SSHKEY"; then + die "error: ssh keyfile '$SSHKEY' not found" +fi + +check_skip() { + case "$SKIP" in + *",$1,"*) return 0 ;; + *) return 1 ;; + esac +} + +if ! check_skip kernel; then + set -- "--customize-hook=$SHARE_DIR/customize-kernel.sh" "$@" +fi + +# construct mmdebstrap options as $@: +set -- \ + --verbose \ + --variant=apt \ + --format=ext2 \ + --include=init \ + "--architecture=$ARCHITECTURE" \ + '--customize-hook=echo "LABEL=debvm / ext4 defaults 0 1" >"$1/etc/fstab"' \ + "$@" + +# set up a hostname +set -- \ + "--customize-hook=echo $VMNAME >"'"$1/etc/hostname"' \ + "--customize-hook=echo 127.0.0.1 localhost $VMNAME >"'"$1/etc/hosts"' \ + "$@" + +# allow password-less root login +set -- '--customize-hook=chroot "$1" passwd --delete root' "$@" + +if ! check_skip systemdnetwork; then + # dhcp on all network interfaces, and add a dns resolver + set -- \ + "--customize-hook=$SHARE_DIR/customize-networkd.sh" \ + '--include=?not(?virtual)?exact-name(libnss-resolve)' \ + "--customize-hook=$SHARE_DIR/customize-resolved.sh" \ + "$@" +fi + +# add ssh key for root +if test -n "$SSHKEY"; then + set -- \ + --include=openssh-server \ + '--customize-hook=mkdir -m700 -p "$1/root/.ssh"' \ + "--customize-hook=upload $SSHKEY /root/.ssh/authorized_keys" \ + "$@" +fi + +if ! check_skip packagelists; then + set -- --skip=cleanup/apt/lists "$@" + set -- "--customize-hook=$SHARE_DIR/customize-dpkgavailable.sh" "$@" +fi + +if test "$SUITE" = jessie; then + # Use obsolete and expired keys. + set -- '--keyring=/usr/share/keyrings/debian-archive-removed-keys.gpg' "$@" + set -- --aptopt='Apt::Key::gpgvcommand "/usr/libexec/mmdebstrap/gpgvnoexpkeysig"' "$@" + set -- --hook-dir=/usr/share/mmdebstrap/hooks/jessie-or-older "$@" +fi + +if ! check_skip usrmerge; then + # Avoid the usrmerge package + set -- --hook-dir=/usr/share/mmdebstrap/hooks/maybe-merged-usr "$@" +fi + +if ! check_skip autologin; then + set -- "--customize-hook=$SHARE_DIR/customize-autologin.sh" "$@" +fi + +set -- "$SUITE" "$IMAGE" "$@" + +set -ex + +mmdebstrap "$@" + +truncate -s ">$SIZE" "$IMAGE" +/sbin/resize2fs "$IMAGE" +/sbin/tune2fs -L debvm -i 0 -O extents,uninit_bg,dir_index,has_journal "$IMAGE" +# Must fsck after tune2fs: https://ext4.wiki.kernel.org/index.php/UpgradeToExt4 +/sbin/fsck.ext4 -fDp "$IMAGE" |