summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHelmut Grohne <helmut@subdivi.de>2023-01-11 19:58:23 +0100
committerHelmut Grohne <helmut@subdivi.de>2023-01-11 19:58:23 +0100
commitdc3527288d6f82ab60cfbe24efeb0961130901b7 (patch)
tree4df30b822078140cec3646421c71208a4646bc4a
parentfe999e3cdb244bef2bd425918bc874b0018e94aa (diff)
parente7c2288400ee78c3ef8c7a92128287c1eff67811 (diff)
downloaddebvm-dc3527288d6f82ab60cfbe24efeb0961130901b7.tar.gz
Merge branch main into skip
Resolve conflicts in the documentation of debvm-create.
-rw-r--r--.gitlab-ci.yml4
-rwxr-xr-xdebvm-create15
-rwxr-xr-xdebvm-run38
-rwxr-xr-xdebvm-waitssh178
-rwxr-xr-xtests/create-and-run.sh2
-rwxr-xr-xtests/dist-upgrades.sh4
-rw-r--r--tests/test_common.sh11
7 files changed, 225 insertions, 27 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d2a1bbf..456e8d9 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -27,7 +27,7 @@ release_test:
script:
- apt-get update
- apt-get dist-upgrade --yes
- - apt-get --no-install-recommends --yes install e2fsprogs genext2fs mmdebstrap openssh-client sleepenh qemu-kvm
+ - apt-get --no-install-recommends --yes install e2fsprogs genext2fs mmdebstrap openssh-client qemu-kvm
- PATH=.:$PATH ./tests/create-and-run.sh $(dpkg --print-architecture) "$RELEASE"
arch_test:
@@ -45,5 +45,5 @@ arch_test:
- test -e /proc/sys/fs/binfmt_misc/status || mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc
- apt-get update
- apt-get dist-upgrade --yes
- - apt-get --no-install-recommends --yes install e2fsprogs genext2fs mmdebstrap openssh-client sleepenh qemu-system binfmt-support arch-test qemu-user-static
+ - apt-get --no-install-recommends --yes install e2fsprogs genext2fs mmdebstrap openssh-client qemu-system binfmt-support arch-test qemu-user-static
- PATH=.:$PATH ./tests/create-and-run.sh "$ARCHITECTURE" sid
diff --git a/debvm-create b/debvm-create
index 5ddbd2f..541519b 100755
--- a/debvm-create
+++ b/debvm-create
@@ -11,7 +11,7 @@ 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> I<sshkey>] [B<-m> I<mirror>] [B<-o> I<output>] [B<-p> I<package>] [B<-r> I<release>] [B<-s> <task>] [B<-z> I<size_in_GB>] [B<--> I<mmdebstrap options>]
+B<debvm-create> [B<-a> I<architecture>] [B<-h> I<hostname>] [B<-k> F<sshkey>] [B<-m> I<mirror>] [B<-o> F<output>] [B<-p> I<package>] [B<-r> I<release>] [B<-s> <task>] [B<-z> I<size_in_GB>] [B<--> I<mmdebstrap options>]
=head1 DESCRIPTION
@@ -37,7 +37,7 @@ A suitable kernel image is automatically selected and installed into the image.
Set the hostname of the virtual machine.
By default, the hostname is B<testvm>.
-=item B<-k> I<sshkey>, B<--sshkey>=I<sshkey>
+=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.
@@ -47,12 +47,12 @@ To connect to the vm, pass a port number to B<debvm-run> with the B<-s> option.
=item B<-m> I<mirror>, B<--mirror>=I<mirror>
Specify the Debian mirror to be used for downloading packages and to be configured inside the virtual machine image.
-By default, B<http://deb.debian.org/debian> is being used.
+By default, L<http://deb.debian.org/debian> is being used.
-=item B<-o> I<output>, B<--output>=I<output>
+=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 B<rootfs.ext4>.
+By default, it is written to F<rootfs.ext4>.
=item B<-p> I<package>, B<--package>=I<package>
@@ -365,6 +365,11 @@ if test "$DEBVER" -ge 12 && ! check_skip usrmerge; then
set -- --hook-dir=/usr/share/mmdebstrap/hooks/merged-usr "$@"
fi
+set -- \
+ '--customize-hook=mkdir "$1/etc/systemd/system/serial-getty@.service.d"' \
+ "--customize-hook=sed -n -e '1i[Service]' -e '1iExecStart=' -e 's,^ExecStart=-/sbin/agetty ,&-a root ,p'"' "$1/lib/systemd/system/serial-getty@.service" > "$1/etc/systemd/system/serial-getty@.service.d/autologin.conf"' \
+ "$@"
+
# suite target mirror
set -- "$@" "$SUITE" "$IMAGE" "deb $MIRROR $SUITE main"
diff --git a/debvm-run b/debvm-run
index 9b64ef4..6f48089 100755
--- a/debvm-run
+++ b/debvm-run
@@ -9,14 +9,14 @@ debvm-run - Run a VM image created by debvm-create
=head1 SYNOPSIS
-B<debvm-run> [B<-g>] [B<-i> I<image>] [B<-s> I<sshport>] [B<--> I<qemu options>]
+B<debvm-run> [B<-g>] [B<-i> F<image>] [B<-s> I<sshport>] [B<--> I<qemu options>]
=head1 DESCRIPTION
B<debvm-run> is essentially a thin wrapper around B<qemu> for running a virtual machine image created by B<debvm-create> or something compatible.
The virtual machine image is expected to be a raw ext4 image with file system label B<debvm>.
-The architecture of the machine is detected from the contained B</bin/true>.
-It must contain a symbolic link pointing to a kernel image at B</vmlinuz> or B</vmlinux> depending on the architecture and a symbolic link pointing to an initrd image at B</initrd.img>.
+The architecture of the machine is detected from the contained F</bin/true>.
+It must contain a symbolic link pointing to a kernel image at F</vmlinuz> or F</vmlinux> depending on the architecture and a symbolic link pointing to an initrd image at F</initrd.img>.
Both are extracted and passed to B<qemu>.
A net interface configured for user mode is added automatically.
@@ -29,10 +29,10 @@ A net interface configured for user mode is added automatically.
By default, the option B<-nographic> is passed to B<qemu> and one interacts with the serial console of the machine.
This configuration is skipped in the presence of this option.
-=item B<-i> I<image>, B<--image>=I<image>
+=item B<-i> F<image>, B<--image>=F<image>
This option specifies the location of the virtual machine image file.
-By default B<rootfs.ext4> in the working directory is used.
+By default F<rootfs.ext4> in the working directory is used.
=item B<-s> I<sshport>, B<--sshport>=I<sshport>
@@ -49,6 +49,32 @@ One possible use of this method is passing B<-snapshot> to avoid modifying the v
=back
+=head1 EXAMPLES
+
+Run a virtual machine stored in the image F<rootfs.ext4> (the default) with
+local port 8022 routed to port 22 of the virtual machine. The B<-snapshot>
+argument is passed to QEMU and prevents any permanent changes to
+F<rootfs.ext4>, resulting in an ephemeral run.
+
+ debvm-run -s 8022 -i rootfs.ext4 -- -snapshot
+
+=head1 FAQ
+
+=over 8
+
+=item The debvm-run console renders wrong.
+
+Get C<echo $LINES $COLUMNS> from an other terminal and run C<stty rows $LINES cols $COLUMNS> in the console or use ssh.
+Another option is to run C<eval $(resize)>, which is available from the B<xterm> package.
+Also set C<$TERM> to the outside value.
+
+=item How can I kill debvm-run?
+
+The wrapped B<qemu> can be terminated by pressing Ctrl-a x.
+Refer to the B<qemu> manual page for more escape sequences.
+
+=back
+
=head1 LIMITATIONS
Due to the way kernel and bootloader are being extracted before running B<qemu>, one cannot upgrade a kernel and then just reboot.
@@ -123,7 +149,7 @@ while getopts :gi:s:-: OPTCHAR; do
usage_error "missing argument for -$OPTARG"
;;
'?')
- usage_erro "unrecognized option -$OPTARG"
+ usage_error "unrecognized option -$OPTARG"
;;
*)
die "internal error while parsing command options, please report a bug"
diff --git a/debvm-waitssh b/debvm-waitssh
new file mode 100755
index 0000000..82eb14d
--- /dev/null
+++ b/debvm-waitssh
@@ -0,0 +1,178 @@
+#!/bin/sh
+# Copyright 2023 Helmut Grohne <helmut@subdivi.de>
+# SPDX-License-Identifier: MIT
+
+: <<'POD2MAN'
+=head1 NAME
+
+debvm-waitssh - Wait for a ssh server to be reachable
+
+=head1 SYNOPSIS
+
+B<debvm-waitssh> [B<-q>] [B<-t> I<timeout>] [I<hostname>:]I<port>
+
+=head1 DESCRIPTION
+
+B<debvm-waitssh> can be used to wait for a virtual machine with exposed ssh port to be reachable on that port.
+If no hostname is given, B<127.0.0.1> is assumed. No authentication is attempted by B<debvm-waitssh>, so neither
+a username nor a key have to be supplied.
+
+=head1 OPTIONS
+
+=over 8
+
+=item B<-t> I<timeout>, B<--timeout>=I<timeout>
+
+Set the maximum duration for waiting in seconds.
+Defaults to one minute.
+
+=item B<-q>, B<--quiet>
+
+Be quiet.
+Do not output a message when the timeout has been reached without success.
+
+=back
+
+=head1 EXIT VALUES
+
+=over 8
+
+=item B<0>
+
+The server is reachable.
+
+=item B<1>
+
+A timeout was reached before the server answered.
+
+=item B<2>
+
+Usage error.
+
+=back
+
+=head1 SEE ALSO
+
+ debvm-run(1)
+
+=cut
+POD2MAN
+
+set -u
+
+TOTALTIMEOUT=60
+SCANTIMEOUT=10
+SCANDELAY=1
+VERBOSITY=1
+
+nth_arg() {
+ shift "$1"
+ printf "%s" "$1"
+}
+
+die() {
+ echo "$*" >&2
+ exit 2
+}
+usage() {
+ die "usage: $0 [-q] [-t <timeout>] [<host>:]<port>"
+}
+usage_error() {
+ echo "error: $*" >&2
+ usage
+}
+
+opt_help() {
+ # shellcheck disable=SC2317 # not dead, called as "opt_$OPTARG"
+ usage
+}
+opt_quiet() {
+ VERBOSITY=0
+}
+opt_timeout() {
+ TOTALTIMEOUT=$1
+}
+
+while getopts :qt:-: OPTCHAR; do
+ case "$OPTCHAR" in
+ q) opt_quiet ;;
+ t) opt_timeout "$OPTARG" ;;
+ -)
+ case "$OPTARG" in
+ help|quiet)
+ "opt_$OPTARG"
+ ;;
+ timeout)
+ test "$OPTIND" -gt "$#" && usage_error "missing argument for --$OPTARG"
+ "opt_$OPTARG" "$(nth_arg "$OPTIND" "$@")"
+ OPTIND=$((OPTIND+1))
+ ;;
+ timeout=)
+ "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))"
+
+test "$#" = 1 || usage
+
+case "$1" in
+ "")
+ usage
+ ;;
+ *:*)
+ HOST=${1%:*}
+ PORT=${1##*:}
+ ;;
+ *)
+ HOST=127.0.0.1
+ PORT=$1
+ ;;
+esac
+
+case "$HOST" in *@*)
+ die "$0: hostname '$HOST' must not contain the '@' character. No username is required."
+;; esac
+
+# Guard against strings containing anything but digits, strings starting with
+# zero and empty strings as the port number.
+#
+# We cannot use [!0-9] because that matches on any character (or possibly
+# multi-character collation element) that sorts in between 0 and 9.
+case "$PORT" in *[!0123456789]*|0?*|""|??????*)
+ die "$0: port '$PORT' is not an integer between 1 and 65535"
+;; esac
+if test "$PORT" -lt 1 -o "$PORT" -gt 65535; then
+ die "$0: port '$PORT' is not an integer between 1 and 65535"
+fi
+
+now=$(date +%s)
+deadline=$((now + TOTALTIMEOUT))
+while test "$now" -lt "$deadline"; do
+ start=$now
+ ssh-keyscan -t rsa -T "$SCANTIMEOUT" -p "$PORT" "$HOST" >/dev/null 2>&1 && exit 0
+ now=$(date +%s)
+ if test "$((now - start))" -lt "$SCANTIMEOUT"; then
+ sleep "$SCANDELAY"
+ now=$(date +%s)
+ fi
+done
+if [ "$VERBOSITY" -ge 1 ]; then
+ echo "$0: timeout reached trying to contact $HOST:$PORT after waiting $TOTALTIMEOUT seconds." >&2
+fi
+exit 1
+
diff --git a/tests/create-and-run.sh b/tests/create-and-run.sh
index 540e6c4..f978052 100755
--- a/tests/create-and-run.sh
+++ b/tests/create-and-run.sh
@@ -26,6 +26,6 @@ SSH_PORT=2222
timeout 240s debvm-run -s "$SSH_PORT" -i "$IMAGE" &
set -- localhost
test "$RELEASE" = jessie && set -- -o PubkeyAcceptedKeyTypes=+ssh-rsa "$@"
-wait_ssh "$@"
+debvm-waitssh -t 150 "$SSH_PORT"
run_ssh "$@" poweroff
wait
diff --git a/tests/dist-upgrades.sh b/tests/dist-upgrades.sh
index 85c9f4a..177712b 100755
--- a/tests/dist-upgrades.sh
+++ b/tests/dist-upgrades.sh
@@ -44,12 +44,12 @@ for RELEASE in stretch buster bullseye bookworm sid; do
timeout 15m debvm-run -s "$SSH_PORT" &
set -- localhost
test "$RELEASE" = stretch && set -- -o PubkeyAcceptedKeyTypes=+ssh-rsa "$@"
- wait_ssh "$@"
+ debvm-waitssh -t 150 "$SSH_PORT"
run_ssh "$@" "upgrade $RELEASE"
wait
done
timeout 5m debvm-run -s "$SSH_PORT" &
-wait_ssh localhost
+debvm-waitssh -t 150 "$SSH_PORT"
run_ssh localhost poweroff
wait
diff --git a/tests/test_common.sh b/tests/test_common.sh
index f42a26a..cba9693 100644
--- a/tests/test_common.sh
+++ b/tests/test_common.sh
@@ -5,14 +5,3 @@ run_ssh() {
test -n "${SSH_PORT:-}" && set -- -p "$SSH_PORT" "$@"
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -l root "$@"
}
-
-wait_ssh() {
- wait_ssh_timeout=5
- wait_ssh_ts=$(sleepenh 0 || [ $? -eq 1 ])
- for _ in $(seq 30); do
- run_ssh -o ConnectTimeout="$wait_ssh_timeout" "$@" echo success && return 0
- wait_ssh_ts=$(sleepenh "$wait_ssh_ts" "$wait_ssh_timeout" || [ $? -eq 1 ])
- done
- echo "timeout reached" >&2
- return 1
-}