#!/bin/bash # # Run ubiquity autopilot tests in KVM # # This script prepares a test environment to run ubiquity autopilot test, run # the tests and collect test artifacts # # Copyright (C) 2013, Canonical Ltd (http://www.canonical.com/) # # Author: Jean-Baptiste Lallement # # This software is free software: you can redistribute it # and/or modify it under the terms of the GNU General Public License # as published by the Free Software Foundation, either version 3 of # the License, or (at your option) any later version. # # This software is distributed in the hope that it will # be useful, but WITHOUT ANY WARRANTY; without even the implied warranty # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this software. If not, see . # set -u RC=0 BINDIR=$(dirname $(readlink -f $0)) DISKSIZE=12G RAMSIZE=2048 VCPU=2 REQUIREDPKGS="bsdtar qemu-system-x86 bzr xz-utils cpio" SHAREDDIR="" OVERRIDEDIR="" WORKSPACE="${WORKSPACE:-/tmp/ubiquity.tests}" TESTNAME="${TESTNAME:-ubiquity_autopilot_tests.tests.test_english_default}" TESTCONFIG="" TIMEOUT=${TIMEOUT:-3600} DELAY=5 SSHPORT=$(shuf -i 2000-65000 -n 1 -z) VNCPORT=$(shuf -i 1-2000 -n 1 -z) VNCOPTS="-vnc localhost:$VNCPORT" QEMUOPTS="-m $RAMSIZE -smp $VCPU \ -localtime -no-reboot \ -net nic,model=virtio -net user -redir tcp:$SSHPORT::22 \ -cpu core2duo \ -daemonize " STARTAT=$(date) ENDAT="" on_exit() { # Exit Handler # # Exit program with status in $RC [ -n "$ENDAT" ] && exit $RC ENDAT=$(date) if [ -f "$WORKDIR/qemu.pid" ]; then echo "I: Terminating qemu" kill -9 $(cat $WORKDIR/qemu.pid) 2>/dev/null fi echo "I: Cleaning working directory" [ -f "$DISKIMG" ] && rm -f "$DISKIMG" [ -d "$WORKDIR" ] && rm -Rf "$WORKDIR" hrule echo -en "Run ended on $ENDAT\n" hrule exit $RC } trap on_exit EXIT INT QUIT ABRT PIPE TERM WORKDIR=$(mktemp -d /tmp/$(basename $0).XXXXXX) DISKDIR=$WORKDIR DISKIMG="" usage() { # Display script usage cat< Prepares a system from an ISO and run autopilot tests for ubiquity Arguments: Path to a valid Ubuntu Desktop ISO Options: -h, --help This help -d, --debug Enable debug mode -D, --shareddir Use source from local directory instead of LP -o, --override PATH Directory to copy into the target filesystem -S, --disksize DISKSIZE Set disk size (default: $DISKSIZE) -s, --shm Write disk image into /dev/shm --sdl Uses SDL instead of VNC by default -t, --test TESTNAME Name of the test to run (default: $TESTNAME) -T, --testconfig FILE Load test configuration from FILE EOF RC=1 && exit } hrule() { seq -s_ 78|tr -d [[:digit:]]; echo; } check_prerequisites() { # Check and set requirements to run this test # # Check and set the requirements to run this test. If any of the # requirement is missing the programs exit with error # # Args: # $@: List of required packages # # Returns # Exit program is a requirement is not met echo "I: Checking system requirements" for pkg in $@; do if ! dpkg-query -W -f'${Status}' $pkg|grep -q "install ok installed" 2>/dev/null; then echo "E: $pkg is required and not installed on this system. Exiting!" RC=1 exit fi done QEMUCMD=$(which qemu-system-x86_64||true) if [ -z "$QEMUCMD" ]; then echo "E: qemu is required and not installed on this system (run sudo apt-get install qemu). Exiting!" RC=1 exit fi QEMUCMD="$(which eatmydata 2>/dev/null||true) $QEMUCMD" QEMUOPTS="$QEMUOPTS -enable-kvm $VNCOPTS" } extract_kernel() { # Extract kernel and initrd # # Extract kernel and initrd from an ISO image # # Args: # $1: Path to a valid ISO # $2: Destination directory src=$1 dst=$2 echo "I: Extracting kernel and initrd from iso" if [ ! -f "$src" ]; then echo "E: The file '$src' does not exists. Exiting!" RC=2 exit fi if [ ! -d "$dst" ]; then echo "E: The directory '$dst' does not exists or is not a directory. Exiting!" RC=2 exit fi files="casper/initrd.lz casper/$(basename $KERNEL)" echo "I: extracting files from $src: $files" bsdtar xf $src -C $dst $files ret=$? if [ $ret -gt 0 ]; then echo "E: bsdtar failed. Aborting!" RC=$ret exit fi } create_disk_image() { # Create a disk image # # Args: # $1: Path of the disk image to create # $2: Size of the disk diskpath=$1 disksize=$2 echo "I: Creating disk image" qemu-img create -f qcow2 $diskpath $disksize ret=$? if [ $ret -gt 0 ]; then echo "E: qemu-img create failed. Aborting!" RC=$ret exit fi } prepare_initrd() { # Put test payload into initrd # # Prepares the initrd and loads a payload that'll botstrap the test # # Args: # $1: working directory # $2: Path to initrd # $3: Path to test directory that contains the override of the target # file system # Returns: # Nothing workdir=$1/initrd initrd=$2 initrdlz=${initrd}.lz usercustomdir=$3 customdir=${BINDIR}/custom-installation echo "I: Preparing initrd" if [ ! -f "$initrdlz" ]; then echo "E: file '$(basename $initrdlz)' not found. Aborting!" RC=1 exit fi mkdir -p $workdir ( cd $workdir xzcat $initrdlz|cpio --quiet -ivd 2>/dev/null echo "I: Copying overrides" cp -af $customdir $workdir/ [ -d "$usercustomdir" ] && cp -af "$usercustomdir" $workdir/ mkdir -p $workdir/custom-installation/iso-override/var/local/autopilot echo "$TESTNAME" > $workdir/custom-installation/iso-override/var/local/autopilot/testsuites [ -f "$TESTCONFIG" ] && cp $TESTCONFIG $workdir/custom-installation/iso-override/var/local/autopilot/config if [ -n "$SHAREDDIR" ]; then echo >> $workdir/custom-installation/iso-override/var/local/autopilot/config echo "SHAREDVOL=ubiquity" >> $workdir/custom-installation/iso-override/var/local/autopilot/config fi echo "I: Repacking initrd" [ -f "$initrd" ] && rm -f $initrd find .|cpio --quiet -o -H newc > $initrd ) } boot_image() { # Boot an image with a iso, a kernel, an initrd and a kernel cmdline # # Args: # $1: Working directory # $1: Path to ISO file # $2: Path to disk image # $3: Path to initrd file # $4: Path to kernel file # $5: Kernel command line workdir=$1 isofile=$2 diskimg=$3 initrd=$4 kernel=$5 cmdline="$6" for f in $2 $3 $4 $5; do if [ ! -f "$f" ]; then echo "E: Required file not found. Aborting!" RC=1 exit fi done echo "I: Booting image" echo "I: local ssh port: $SSHPORT" [ -n "$SHAREDDIR" ] && QEMUOPTS="$QEMUOPTS -virtfs local,id=ubiquity,path=${SHAREDDIR},security_model=none,mount_tag=ubiquity" $QEMUCMD $QEMUOPTS -drive file=$diskimg,if=virtio -cdrom $isofile -boot d \ -initrd $initrd -kernel $kernel -append "$cmdline" \ -serial file:$workdir/ubiquity.ttyS0 \ -serial file:$workdir/ubiquity.ttyS1 \ -pidfile $workdir/qemu.pid } collect_artifacts() { echo "I: Collecting test artifacts" [ $# -eq 0 ] && return [ -z "$WORKSPACE" ] && return resultdir=$WORKSPACE/results/ mkdir -p $resultdir rsync -avH $@ $resultdir if [ -f "$resultdir/artifacts.tgz" ]; then echo "I: Extracting artifacts to result directory" tar xzf $resultdir/artifacts.tgz -C $resultdir/ rm -f "$resultdir/artifacts.tgz" fi find $resultdir | xargs touch echo "I: Artifacts stored in $resultdir" } tail_logs() { # Tail log files in -F mode in background # # $@ List of log files for log in $@; do #tail -n0 -F --pid=$$ $log | mawk -Winteractive -v logfile="$log" '{print logfile":",$0}' & tail -n0 -F --pid=$$ $log & done } SHORTOPTS="hdDo:S:st:T:" LONGOPTS="help,debug,shareddir,override:,disksize:,sdl,shm,test:,testconfig:" TEMP=$(getopt -o $SHORTOPTS --long $LONGOPTS -- "$@") eval set -- "$TEMP" exec 2>&1 while true ; do case "$1" in -h|--help) usage;; -d|--debug) set -x shift;; -D|--shareddir) SHAREDDIR=$(readlink -f $BINDIR/../..) shift;; -o|--override) OVERRIDEDIR=$2 shift 2;; -S|--disksize) DISKSIZE=$2 shift 2;; -s|--shm) DISKDIR=/dev/shm shift;; --sdl) VNCOPTS="" shift;; -t|--test) TESTNAME=$2 shift 2;; -T|--testconfig) TESTCONFIG=$(readlink -f $2) if [ ! -f "$TESTCONFIG" ]; then echo "E: Configuration file not found :'$TESTCONFIG'. Aborting!" exit 1 fi shift 2;; --) shift; break;; *) usage;; esac done [ $# -ne 1 ] && usage ISO="$1" hrule cat</dev/null 2>&1; then KERNEL=${KERNEL}.efi fi KERNELOPTS="boot=casper DEBCONF_DEBUG=developer -- debconf/priority=critical locale=en_US console-setup/ask_detect=false console-setup/layoutcode=us automatic-ubiquity" KERNELOPTS="boot=casper DEBCONF_DEBUG=developer -- debconf/priority=critical locale=en_US console-setup/ask_detect=false console-setup/layoutcode=us noprompt console=ttyS0,115200" check_prerequisites $REQUIREDPKGS extract_kernel $ISO $WORKDIR create_disk_image $DISKIMG $DISKSIZE prepare_initrd $WORKDIR ${INITRD} "$OVERRIDEDIR" boot_image $WORKDIR $ISO $DISKIMG ${INITRD} $KERNEL "$KERNELOPTS" tail_logs $WORKDIR/ubiquity.ttyS0 PIDFILE=$WORKDIR/qemu.pid while sleep $DELAY; do if [ ! -f "$PIDFILE" ]; then echo "I: PID file not found: $PIDFILE" break fi if ! kill -0 $(cat $WORKDIR/qemu.pid) 2>/dev/null; then echo "I: Qemu process terminated." break fi TIMEOUT=$((TIMEOUT - DELAY)) if [ $TIMEOUT -le 0 ]; then echo "E: Test Timed out!" break fi done mkdir -p $WORKDIR/logs cp $WORKDIR/ubiquity.ttyS0 $WORKDIR/logs/console cp $WORKDIR/ubiquity.ttyS1 $WORKDIR/logs/artifacts.tgz collect_artifacts $WORKDIR/logs/