From cb3b9b92b1464bd1e4c17a2ca3b78f8dbc9b8b1f Mon Sep 17 00:00:00 2001 From: Michael Prokop Date: Sat, 17 Aug 2024 14:14:08 +0200 Subject: [PATCH] tests: Try to capture screenshot via VNC if serial-console-connection fails While debugging the failing GitHub Actions (see #278), we noticed that it might serve useful to have a screenshot of the booted system available. We can capture such a screenshot via vncsnapshot. NOTE: we move the files inside `results` only if the directory as such exists in $PWD, otherwise we'd fail the build when being executed as `tests/build-vm-and-test.sh test` from inside the grml-debootstrap.git. This happens when manually reproducing the GH tests, though then `build-vm-and-test.sh` is supposed to be executed from the parent directory of the `tests` directory (being the grml-debootstrap.git checkout). --- tests/build-vm-and-test.sh | 2 ++ tests/serial-console-connection | 25 ++++++++++++++++++++++++- tests/test-vm.sh | 13 +++++++++++-- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/tests/build-vm-and-test.sh b/tests/build-vm-and-test.sh index 1fb604d..c88c6c5 100755 --- a/tests/build-vm-and-test.sh +++ b/tests/build-vm-and-test.sh @@ -34,6 +34,8 @@ fi if [ "$1" == "setup" ]; then sudo apt-get update sudo apt-get -qq -y install curl qemu-system-x86 kpartx python3-pexpect python3-serial + # vncsnapshot might not be available, though we don't want to abort execution then + sudo apt-get -qq -y install vncsnapshot || true [ -x ./tests/goss ] || curl -fsSL https://goss.rocks/install | GOSS_DST="$(pwd)/tests" sh # TODO: docker.io exit 0 diff --git a/tests/serial-console-connection b/tests/serial-console-connection index 1aaf5d4..f2ffbc1 100755 --- a/tests/serial-console-connection +++ b/tests/serial-console-connection @@ -1,8 +1,11 @@ #!/usr/bin/env python3 import argparse import multiprocessing +import os import pexpect import serial +import shutil +import subprocess import sys import time from pexpect import fdpexpect, TIMEOUT @@ -19,6 +22,8 @@ parser.add_argument('--user', default="root", help='user name to use for login (default: root)') parser.add_argument('--password', default="grml", help='password for login (default: grml)') +parser.add_argument('--screenshot', default="screenshot.jpg", + help='file name for screenshot captured via VNC on error (default: screenshot.jpg)') parser.add_argument('--tries', default="12", type=int, help='Number of retries for finding the login prompt') parser.add_argument('--timeout', default="300", type=int, @@ -64,6 +69,21 @@ def login(ser, hostname, user, password, timeout=5): child.expect("%s@%s" % (user, hostname), timeout=timeout) +def capture_vnc_screenshot(screenshot_file): + if not shutil.which('vncsnapshot'): + print("WARN: vncsnapshot not available, skipping vnc snapshot capturing.") + return(0) + + print("Trying to capture screenshot via vncsnapshot") + + proc = subprocess.Popen(["vncsnapshot", "localhost", screenshot_file]) + proc.wait() + if proc.returncode != 0: + print("WARN: failed to capture vnc snapshot :(") + else: + print("Screenshot file '%s' available" % os.path.abspath(screenshot_file)) + + def main_login(args, ser, hostname, user, password, port, commands): success = False for i in range(args.tries): @@ -102,6 +122,7 @@ def main(): user = args.user commands = args.command timeout = args.timeout + screenshot_file = args.screenshot ser = serial.Serial(port, 115200) ser.flushInput() @@ -112,8 +133,10 @@ def main(): process.join(timeout=timeout) if process.is_alive(): - print("Reached timeout of %s seconds, aborting." % timeout) + print("Reached timeout of %s seconds" % timeout) + capture_vnc_screenshot(screenshot_file) process.terminate() + print("Giving up serial-console-connection execution now") sys.exit(1) diff --git a/tests/test-vm.sh b/tests/test-vm.sh index d838801..e59a1d9 100755 --- a/tests/test-vm.sh +++ b/tests/test-vm.sh @@ -114,13 +114,15 @@ if [ "$success" = "0" ] ; then exit 1 fi +RC=0 "$TEST_PWD"/tests/serial-console-connection \ + --screenshot "$TEST_PWD/tests/screenshot.jpg" \ --timeout 300 \ --tries 60 \ --port "$serial_port" \ --hostname "$VM_HOSTNAME" \ --poweroff \ - "mount -t 9p -o trans=virtio,version=9p2000.L,rw $MOUNT_TAG /mnt && cd /mnt && ./testrunner" + "mount -t 9p -o trans=virtio,version=9p2000.L,rw $MOUNT_TAG /mnt && cd /mnt && ./testrunner" || RC=$? if [ ! -d results ] || [ ! -f ./results/goss.tap ] || [ ! -f ./results/goss.exitcode ]; then echo "Running tests inside VM failed for unknown reason" >&2 @@ -134,7 +136,14 @@ fi echo "Finished serial console connection [timeout=${timeout}]." -mv results/* "$TESTS_RESULTSDIR/" +# in case of errors we might have captured a screenshot via VNC +if [ -r "${TEST_PWD}"/tests/screenshot.jpg ] ; then + cp "${TEST_PWD}"/tests/screenshot.jpg "${TESTS_RESULTSDIR}" +fi + +if [ -d results ] ; then + mv results/* "$TESTS_RESULTSDIR/" +fi bailout $RC