This patch is more robust, ensuring that VMs and bridges are removed once the tests complete. It also will exit immediately after a failed test.
Darryl L. Pierce
2009-May-01 18:14 UTC
[Ovirt-devel] [PATCH node-image] Added new autotests and refactored the autotest script.
Completely reworked the tests so that it would be easier to add or extend tests. Added commandline arguments to enable debugging of tests, open virt-viewer on a test vm while it's running. specify different ISOs to test, run just a single or small set of tests, and to make the script itself more robust. Signed-off-by: Darryl L. Pierce <dpierce at redhat.com> --- autotest.sh | 856 +++++++++++++++++++++++++++++++++++------------------------ 1 files changed, 509 insertions(+), 347 deletions(-) diff --git a/autotest.sh b/autotest.sh index 6cba9fa..f256a22 100755 --- a/autotest.sh +++ b/autotest.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # oVirt node image autotest script # @@ -36,71 +36,235 @@ # This will, for each module whose autobuild.sh is run, to have a matching # autotest.sh to run as well. # -# To run the test locally, all that's needed is for an ISO file named ovirt-node-image.iso -# be present in the local directory. This will then be put through its paces with test -# results being send to stdout. +# To run these tests locally, you will need to open port 69 TCP and UDP and have +# an ISO file. ME=$(basename "$0") warn() { printf '%s: %s\n' "$ME" "$*" >&2; } die() { warn "$*"; exit 1; } +debug() { if $debugging; then log "[DEBUG] %s" "$*"; fi } -# trap '__st=$?; stop_log; exit $__st' 0 -trap '__st=$?; log "Exiting normally."; cleanup; exit $__st' 0 -trap '__st=$?; log "Dying a horrible death."; cleanup; exit $__st' 1 2 13 15 +trap '__st=$?; cleanup_after_testing; exit $__st' 1 2 3 13 15 +trap 'cleanup_after_testing' 0 -test -n "$1" && RESULTS=$1 || RESULTS=autotest.log +# set -e +# set -u -echo "Running oVirt node image Autotest" +log () { + date=$(date) + printf "${date} $*\n" +} -# BZ#495954 needs to be fixed to uncomment this -# set -e -# set -v +usage () { + cat <<EOF +Usage: $ME [-n test_name] [LOGFILE] + -i: set the ISO filename (defualt: ovirt-node-image.iso) + -n: the name of the specific autotest to run (default: run all autotests) + -d: enable more verbose output (default: disabled) + -v: enable tracing (default: disabled) + -w: launch virt-viewer for each VM (default: no window shown) + -h: display this help and exit +EOF +} -OVIRT_NODE_IMAGE_ISO=$PWD/ovirt-node-image.iso +# $1 - the test function to call +execute_test () { + local testname=$1 -if [ ! -f $OVIRT_NODE_IMAGE_ISO ]; then - die "Missing ovirt-node-image.iso file!" -fi + if [ -z $testname ]; then die "Missing test name"; fi -log () { - local text="`date` $*" - printf "${text}\n" - # sudo bash -c "printf \"[$$] ${text}\n\" >> ${RESULTS}" + log "Executing test: $testname" + + eval $testname + + rc=$? + log "Completed test: $testname [result=$rc]" + + if [ $rc -ne 0 ]; then + log "Build fails smoke tests." + exit 1 + fi + + return $rc } -cleanup () { - log "CLEANING UP" +# setup a node for pxeboot +# $1 - the working directory +# $2 - kernel arguments; if present then they replace all default flags +setup_pxeboot () { + local workdir=$1 + local kernelargs=$2 + local pxedefault=$workdir/tftpboot/pxelinux.cfg/default + + debug "setup for pxeboot: isofile=${isofile} workdir=${workdir} kernelargs='${kernelargs}' pxedefault=${pxedefault}" + (cd $workdir && sudo livecd-iso-to-pxeboot $isofile) > /dev/null 2>&1 + sudo chmod -R 777 $workdir + + # set default kernel arguments if none were provided + # the defaults boot in standalone mode + if [ -z "$kernelargs" ]; then + kernelargs="ovirt_standalone" + fi + + local definition="DEFAULT pxeboot" + definition="${definition}\nTIMEOUT 20" + definition="${definition}\nPROMPT 0" + definition="${definition}\nLABEL pxeboot" + definition="${definition}\n KERNEL vmlinuz0" + definition="${definition}\n IPAPPEND 2" + definition="${definition}\n APPEND rootflags=loop initrd=initrd0.img root=/${isoname} rootfstype=auto console=tty0 check console=ttyS0,115200n8 $kernelargs" + + debug "pxeboot definition=\n${definition}" + sudo bash -c "printf \"${definition}\" > $pxedefault" +} + +# Starts a simple instance of dnsmasq. +# $1 - the iface on which dnsmasq works +# $2 - the root for tftp files +# $3 - the mac address for the node (ignored if blank) +# $4 - the nodename +start_dnsmasq () { + local iface=$1 + local tftproot=$2 + local macaddress=$3 + local nodename=$4 + local pidfile=$2/dnsmasq.pid + stop_dnsmasq - destroy_test_iface + debug "Starting dnsmasq" + dns_startup="sudo /usr/sbin/dnsmasq --read-ethers + --dhcp-range=${NETWORK}.100,${NETWORK}.254,255.255.255.0,24h + --interface=${iface} + --bind-interfaces + --except-interface=lo + --dhcp-boot=tftpboot/pxelinux.0 + --enable-tftp + --tftp-root=${tftproot} + --log-facility=/tmp/dnsmasq-${nodename}.log + --log-queries + --log-dhcp + --pid-file=${pidfile}" + if [ -n "$macaddress" ]; then + dns_startup="${dns_startup} --dhcp-host=${macaddress},${NODE_ADDRESS}" + fi + # start dnsmasq + eval $dns_startup + debug "pidfile=$pidfile" + DNSMASQ_PID=$(sudo cat $pidfile) + debug "DNSMASQ_PID=${DNSMASQ_PID}" } -# Creates a HD disk file. +# Kills the running instance of dnsmasq. +stop_dnsmasq () { + if [ -n "${DNSMASQ_PID-}" -a "${DNSMASQ_PID-}" != "0" ]; then + local check=$(ps -ef | awk "/${DNSMASQ_PID}/"' { if ($2 ~ '"${DNSMASQ_PID}"') print $2 }') + + if [[ "${check}" == "${DNSMASQ_PID}" ]]; then + sudo kill -9 $DNSMASQ_PID + return + fi + fi + DNSMASQ_PID="0" +} + +# Creates a virt network. +# $1 - the node name +# $2 - the network interface name +# $3 - use DHCP (any value) +# $4 - start dnsmsq (def. false) +start_networking () { + local nodename=$1 + local ifacename=$2 + local use_dhcp=${3-false} + local start_dnsmasq=${4-false} + local workdir=$5 + local definition="" + local network=$NETWORK + local xmlfile=$(mktemp) + + debug "start_networking ()" + for var in nodename ifacename use_dhcp start_dnsmasq workdir network xmlfile; do + eval debug "::$var: \$$var" + done + + definition="<network>\n<name>${ifacename}</name>\n<forward mode='nat' />\n<bridge name='${ifacename}' stp='on' forwardDelay='0' />" + definition="${definition}\n<ip address='${network}.1' netmask='255.255.255.0'>" + if $use_dhcp; then + definition="${definition}\n<dhcp>\n<range start='${network}.100' end='${network}.199' />\n</dhcp>" + fi + definition="${definition}\n</ip>\n</network>" + + debug "Saving network definition file to: ${xmlfile}\n" + sudo printf "${definition}" > $xmlfile + sudo virsh net-define $xmlfile > /dev/null 2>&1 + debug "Starting network." + sudo virsh net-start $ifacename > /dev/null 2>&1 + + if [ "${use_dhcp}" == "false" ]; then + if $start_dnsmasq; then + start_dnsmasq $ifacename $workdir "" $nodename + fi + fi +} + +# Destroys the test network interface +# $1 - the network name +# $2 - stop dnsmasq (def. false) +stop_networking () { + local networkname=${1-} + local stop_dnsmasq=${2-true} + + # if no network was supplied, then check for the global network + if [ -z "$networkname" ]; then + networkname=${NETWORK_NAME-} + fi + + if [ -n "${networkname}" ]; then + debug "Destroying network interface: ${networkname}" + check=$(sudo virsh net-list --all) + if [[ "${check}" =~ "${networkname}" ]]; then + if [[ "{$check}" =~ active ]]; then + sudo virsh net-destroy $networkname > /dev/null 2>&1 + fi + sudo virsh net-undefine $networkname > /dev/null 2>&1 + fi + fi + + if $stop_dnsmasq; then + stop_dnsmasq + fi +} + +# creates a HD disk file # $1 - filename for disk file -# $2 - size +# $2 - size (##M or ##G) create_hard_disk () { local filename=$1 local size=$2 - sudo qemu-img create -f raw $filename $size - sudo chcon -t virt_image_t $filename + debug "Creating hard disk: filename=${filename} size=${size}" + sudo qemu-img create -f raw $filename "${size}M" > /dev/null 2>&1 + sudo chcon -t virt_image_t $filename > /dev/null 2>&1 } # Creates the XML for a virtual machine. # $1 - the file to write the xml # $2 - the node name -# $3 - memory size (in bytes) -# $4 - the local hard disk (if blank then no disk is used) -# $5 - the cdrom disk (if blank then no cdrom is used) -# $6 - the network bridge (if blank then 'default' is used) -# $7 - optional arguments +# $3 - memory size (in kb) +# $4 - boot device +# $5 - the local hard disk (if blank then no disk is used) +# $6 - the cdrom disk (if blank then no cdrom is used) +# $7 - the network bridge (if blank then 'default' is used) +# $8 - optional arguments define_node () { local filename=$1 local nodename=$2 local memory=$3 - local harddrive=$4 - local cddrive=$5 - local bridge=$6 - local options=$7 + local boot_device=$4 + local harddrive=$5 + local cddrive=$6 + local bridge=${7-default} + local options=${8-} local result="" # flexible options @@ -111,23 +275,28 @@ define_node () { local vncport="-1" local bootdev='hd' - # if a cdrom was defined, then assume it's the boot device - if [ -n "$cddrive" ]; then bootdev='cdrom'; fi + # first destroy the node + destroy_node $nodename if [ -n "$options" ]; then eval "$options"; fi + debug "define_node ()" + for var in filename nodename memory harddrive cddrive bridge options arch emulator serial vncport bootdev; do + eval debug "::$var: \$$var" + done + result="<domain type='kvm'>\n<name>${nodename}</name>\n<memory>${memory}</memory>\n <vcpu>1</vcpu>" # begin the os section # inject the boot device result="${result}\n<os>\n<type arch='${arch}' machine='pc'>hvm</type>" - result="${result}\n<boot dev='${bootdev}' />" + result="${result}\n<boot dev='${boot_device}' />" result="${result}\n</os>" # virtual machine features result="${result}\n<features>" result="${result}\n<acpi />" - if [ -z "${noapic}" ]; then result="${result}\n<apic />"; fi + if [ -z "${noapic-}" ]; then result="${result}\n<apic />"; fi result="${result}\n<pae /></features>" result="${result}\n<clock offset='utc' />" result="${result}\n<on_poweroff>destroy</on_poweroff>" @@ -139,6 +308,7 @@ define_node () { result="${result}\n<emulator>${emulator}</emulator>" # inject the hard disk if defined if [ -n "$harddrive" ]; then + debug "Adding a hard drive to the node" result="${result}\n<disk type='file' device='disk'>" result="${result}\n<source file='$harddrive' />" result="${result}\n<target dev='vda' bus='virtio' />" @@ -146,6 +316,7 @@ define_node () { fi # inject the cdrom drive if defined if [ -n "$cddrive" ]; then + debug "Adding a CDROM drive to the node" result="${result}\n<disk type='file' device='cdrom'>" result="${result}\n<source file='${cddrive}' />" result="${result}\n<target dev='hdc' bus='ide' />" @@ -169,398 +340,389 @@ define_node () { result="${result}\n</domain>" - log "Saving node definition to file: ${filename}" + debug "Node definition: ${filename}" sudo printf "$result" > $filename # now define the vm - sudo virsh define $filename + sudo virsh define $filename > /dev/null 2>&1 if [ $? != 0 ]; then die "Unable to define virtual machine: $nodename"; fi } -# Returns the mac address for the given node. -# $1 - the node name -# $2 - the variable name to set -get_mac_address () { - local nodename=$1 - local varname=$2 - - if [ -z "$nodename" ]; then die "Cannot get mac address for node with a name"; fi - - address=$(sudo virsh dumpxml $nodename|awk '/<mac address/ { - match($0,"mac address='"'"'(.*)'"'"'",data); print data[1]}') - - if [ -z "$varname" ]; then die "Cannot set unnamed varilable"; fi - eval $varname="$address" -} - -# Starts the named node. # $1 - the node name -start_node () { +# $2 - the boot device (def. "hd") +# $3 - the memory size in kb (def. 524288) +# $4 - hard disk size (if blank then no hard disk) +# $5 - the cd drive image file (if blank then no cd drive) +# $6 - option arguments +configure_node () { local nodename=$1 + local boot_device=$2 + local memory=$3 + local hdsize=$4 + local hdfile="" + local cdfile=$5 + local args=$6 + local nodefile=$(mktemp) + + if [ -z "${boot_device}" ]; then boot_device="hd"; fi + if [ -z "${memory}" ]; then memory="524288"; fi + + debug "configure_node ()" + for var in nodename boot_device memory hdsize hdfile cdfile args nodefile; do + eval debug "::$var: \$$var" + done + + # create the hard disk file + if [ -n "${hdsize}" ]; then + hdfile=$(mktemp) + create_hard_disk $hdfile $hdsize + fi - if [ -z "$nodename" ]; then die "Cannot start node without a name"; fi - - sudo virsh start $nodename + define_node $nodefile $nodename "${memory}" "${boot_device}" "${hdfile}" "${cdfile}" $IFACE_NAME "${args}" } -# Destroys any existing instance of the given node. # $1 - the node name +# $2 - undefine the node (def. true) destroy_node () { local nodename=$1 + local undefine=${2-true} if [ -n "${nodename}" ]; then - log "Destroying VM: ${nodename}" check=$(sudo virsh list --all) if [[ "${check}" =~ "${nodename}" ]]; then if [[ "${check}" =~ running ]]; then - sudo virsh destroy $nodename + sudo virsh destroy $nodename > /dev/null 2>&1 + fi + if $undefine; then + sudo virsh undefine $nodename > /dev/null 2>&1 fi - sudo virsh undefine $nodename fi fi } -# PXE boots a node. -# $1 - the ISO file -# $2 - the working directory -# $3 - kernel arguments; if present then they replace all default flags -setup_pxeboot () { - local isofile=$1 - local workdir=$2 - local kernelargs=$3 - local pxedefault=$workdir/tftpboot/pxelinux.cfg/default - - (cd $workdir && sudo livecd-iso-to-pxeboot $isofile) - sudo chmod -R 777 $workdir +# for each test created, add it to the follow array: +tests=''; testcount=0; - # set default kernel arguments if none were provided - # the defaults boot in standalone mode - if [ -z "$kernelargs" ]; then - kernelargs="ovirt_standalone" - fi +# $1 - test name +add_test () { + tests[$testcount]=$1 + testcount=$testcount+1 +} - local definition="DEFAULT pxeboot\nTIMEOUT 20\nPROMPT 0\nLABEL pxeboot\n KERNEL vmlinuz0\n IPAPPEND 2\n APPEND rootflags=loop BOOTIF=link|eth*|<MAC> initrd=initrd0.img root=/ovirt-node-image.iso rootfstype=auto console=ttyS0,115200n8 $kernelargs\n" +# $1 - node name +start_virt_viewer () { + local nodename=$1 - sudo bash -c "printf \"${definition}\" > $pxedefault" + sudo virt-viewer $nodename > /dev/null 2>&1& } -# Launches the node as a virtual machine. -# $1 - the node name -# $2 - the ISO filename -# $3 - the hard disk file -# $4 - the memory size (in MB) -# $5 - the network bridge to use -# $6 - kernel arguments -# $7 - verification method -pxeboot_node_vm () { +# $1 - the node's name +# $2 - kernel arguments +# $3 - working directory +boot_with_pxe () { local nodename=$1 - local isofile=$2 - local diskfile=$3 - local memsize=$4 - local bridge=$5 - local kernel_args=$6 - local verify_method=$7 - local xmlfile=$(mktemp) - local tftproot=$(mktemp -d) - local node_mac_address="" - local return_code=0 + local kernel_args=$2 + local workdir=$3 - destroy_node $nodename + debug "boot_with_pxe ()" + debug "- workdir: ${workdir}" + debug "- nodename: ${nodename}" + debug "- kernel_args: ${kernel_args}" - log "Beginning pxeboot for $nodename" - # setup the dnsmasq instance with the iso setup - setup_pxeboot "$isofile" "$tftproot" "$kernel_args" - create_test_iface $bridge - define_node $xmlfile $nodename $memsize "$diskfile" "" $bridge "local bootdev='network'; local noapic='yes'" - get_mac_address $nodename "node_mac_address" - start_dnsmasq $bridge $tftproot $node_mac_address $nodename - start_node $nodename - if [ -n "$verify_method" ]; then - eval $verify_method - return_code=$? - fi - destroy_node $nodename - stop_dnsmasq - destroy_test_iface $bridge - log "Finished pxeboot for $nodename (RC=${return_code})" + setup_pxeboot $workdir "${kernel_args}" - if [ $return_code != 0 ]; then - log "Test ended in failure" + sudo virsh start $nodename > /dev/null 2>&1 + if $show_viewer; then + start_virt_viewer $nodename fi - - test $return_code == 0 && return 0 || return 1 } -# Launches the node as a virtual machine with a CDROM. -# $1 - the node name -# $2 - the ISO filename -# $3 - the disk file to use -# $4 - the memory size (in MB) -# $5 - the network bridge -cdrom_boot_node_vm () { +# $1 - the node's name +boot_from_hd () { local nodename=$1 - local isofile=$2 - local diskfile=$3 - local memsize=$4 - local bridge=$5 - local xmlfile=$(mktemp) - destroy_node $nodename + debug "boot_from_hd ()" + debug "::nodename: ${nodename}" - log "Beginning cdrom boot for $nodename" - create_test_iface $bridge "yes" - define_node $xmlfile $nodename $memsize "$diskfile" "$isofile" $bridge - start_node $nodename - # TODO make sure the node's booted - sleep 300 - # TODO verify the node's running - destroy_node $nodename - destroy_test_iface $bridge - log "Finished cdrom booting for $nodename" + sudo virsh start $nodename > /dev/null 2>&1 + if $show_viewer; then + start_virt_viewer $nodename + fi } -# Creates a virt network. -# $1 - the network interface name -# $2 - use DHCP (any value) -create_test_iface () { - local name=$1 - local dhcp=$2 - local definition=$(mktemp) - local network=$NETWORK - local definition="" - local xmlfile=$(mktemp) +# $1 - the node name +# $2 - the old boot device +# $3 - the new boot device +substitute_boot_device () { + local nodename=$1 + local old_device=$2 + local new_device=$3 + local new_node_file=$(mktemp) - destroy_test_iface $name - NETWORK_NAME=$name + if [ -n "${nodename}" ]; then + local xml=$(sudo virsh dumpxml $nodename | sed "s/boot dev='"${old_device}"'/boot dev='"${new_device}"'/") - log "Creating network definition file: $definition" - definition="<network>\n<name>${name}</name>\n<forward mode='nat' />\n<bridge name='${name}' stp='on' forwardDelay='0' />" - definition="${definition}\n<ip address='${network}.1' netmask='255.255.255.0'>" - if [ -n "$dhcp" ]; then - definition="${definition}\n<dhcp>\n<range start='${network}.100' end='${network}.199' />\n</dhcp>" - fi - definition="${definition}\n</ip>\n</network>" + sudo printf "${xml}" > $new_node_file - printf "Saving network definition file to: ${xmlfile}\n" - sudo printf "${definition}" > $xmlfile - sudo virsh net-define $xmlfile - log "Starting network" - sudo virsh net-start $name + sudo virsh define $new_node_file + fi } -# Destroys the test network interface -# $1 - the network name -destroy_test_iface () { - local networkname=$1 +add_test "test_stateless_pxe_with_nohd" +test_stateless_pxe_with_nohd () { + local nodename="${vm_prefix}-stateless-pxe-nohd" + local workdir=$(mktemp -d) - # if no network was supplied, then check for the global network - if [ -z "$networkname" ]; then - networkname=$NETWORK_NAME - fi + start_networking $nodename $IFACE_NAME false true $workdir - if [ -n "${networkname}" ]; then - log "Destroying network interface: ${networkname}" - check=$(sudo virsh net-list --all) - if [[ "${check}" =~ "${networkname}" ]]; then - log "- found existing instance" - if [[ "{$check}" =~ active ]]; then - log "- shutting down current instance" - sudo virsh net-destroy $networkname - fi - log "- undefining previous instance" - sudo virsh net-undefine $networkname - fi + configure_node "${nodename}" "network" "" "" "" "local noapic=true" + boot_with_pxe "${nodename}" "firstboot=no" "${workdir}" - # ensure the bridge interface was destroyed - check=$(sudo /sbin/ifconfig) - if [[ "${check}" =~ "${networkname}" ]]; then - sudo /sbin/ifconfig $networkname down - fi - fi -} + expect -c ' +set timeout 120 +log_file -noappend stateless-pxe-nohd.log -# Starts a simple instance of dnsmasq. -# $1 - the iface on which dnsmasq works -# $2 - the root for tftp files -# $3 - the mac address for the node (ignored if blank) -# $4 - the nodename -start_dnsmasq () { - local iface=$1 - local tftproot=$2 - local macaddress=$3 - local nodename=$4 - local pidfile=$2/dnsmasq.pid +spawn sudo virsh console '"${nodename}"' - stop_dnsmasq - log "Starting dnsmasq" - dns_startup="sudo /usr/sbin/dnsmasq --read-ethers - --dhcp-range=${NETWORK}.100,${NETWORK}.254,255.255.255.0,24h - --interface=${iface} - --bind-interfaces - --except-interface=lo - --dhcp-boot=tftpboot/pxelinux.0 - --enable-tftp - --tftp-root=${tftproot} - --log-facility=/tmp/dnsmasq-${nodename}.log - --log-queries - --log-dhcp - --pid-file=${pidfile}" - if [ -n "$macaddress" ]; then - dns_startup="${dns_startup} --dhcp-host=${macaddress},${NODE_ADDRESS}" - fi - # start dnsmasq - eval $dns_startup - DNSMASQ_PID=$(sudo cat $pidfile) - log "dnsmasq start: PID=${DNSMASQ_PID}" +expect { + -exact "Linux version" { send_log "\n\nMarker 1\n\n"; exp_continue } + -exact "Starting ovirt-early:" { send_log "\n\nMarker 2\n\n"; exp_continue } + -exact "Starting ovirt:" { send_log "\n\nMarker 3\n\n"; exp_continue } + -exact "Starting ovirt-post:" { send_log "\n\nMarker 4\n\n"; exp_continue } + -exact "login:" { send_log "\n\nMarker 5\n\n"; exit } + timeout { + send_log "\nMarker not found.\n\n" + exit 1 + } eof { + send_log "Unexpected end of file." + exit 2 + } + + send_log \"\n\nUnexpected end of interaction.\n\n\" + exit 3 } +' -# Kills the running instance of dnsmasq. -stop_dnsmasq () { - log "Killing dnsmasq: DNSMASQ_PID=${DNSMASQ_PID}" - if [ -n "$DNSMASQ_PID" -a "$DNSMASQ_PID" != "0" ]; then - local check=$(ps -ef | awk "/${DNSMASQ_PID}/"' { if ($2 ~ '"${DNSMASQ_PID}"') print $2 }') + result=$? - if [[ "${check}" == "${DNSMASQ_PID}" ]]; then - log "Killing dnsmasq" - sudo kill -9 $DNSMASQ_PID - return - fi - fi - log "No running instance of dnsmasq found." - DNSMASQ_PID="0" + destroy_node $nodename + stop_networking $IFACE_NAME true + + return $result } -# Boots a node via CDROM. -# $1 - the node name -# $2 - the network to use -# $3 - the working directory -# $4 - the ISO file to use as CDROM -cdrom_boot () { - local nodename=$1 - local network=$2 - local workdir=$3 - local isofile=$4 - local diskfile=$workdir/ovirt-harddisk.img +add_test "test_stateless_pxe" +test_stateless_pxe () { + local nodename="${vm_prefix}-stateless-pxe" + local workdir=$(mktemp -d) - create_hard_disk $diskfile "10G" - cdrom_boot_node_vm $nodename $isofile $diskfile "512" $network -} + start_networking $nodename $IFACE_NAME false true $workdir -# verify that a node has booted properly -# $1 - the node's name -# $2 - the logfile to use -verify_pxeboot_stateless_standalone () { - local nodename=$1 - local port=$(sudo virsh ttyconsole $nodename) - local logfile=$2 + configure_node "${nodename}" "network" "" "10000" "" "local noapic=true" + boot_with_pxe "${nodename}" "firstboot=no" "${workdir}" + + expect -c ' +set timeout 120 + +log_file -noappend stateless-pxe.log + +spawn sudo virsh console '"${nodename}"' - log "Verifying ${nodename} is booted correctly" - local script=' -log_file -noappend '"${logfile}"' -set timeout 60 -expect { - "Linux version" {send_log "\n\n***\nGot first boot marker\n\n"} - timeout {send_log "\n\n***\nDid not receive in time\n\n" - exit 1} -} expect { - -re "Kernel command line.*ovirt_standalone" {send_log "\n\n***\nGot kernel arguments marker\n\n"} + -exact "Linux version" { send_log "\n\nMarker 1\n\n"; exp_continue } + -exact "Starting ovirt-early:" { send_log "\n\nMarker 2\n\n"; exp_continue } + -exact "Starting ovirt:" { send_log "\n\nMarker 3\n\n"; exp_continue } + -exact "Starting ovirt-post:" { send_log "\n\nMarker 4\n\n"; exp_continue } + -re "localhost.*login:" { send_log "\n\nMarker 5\n\n"; exit } timeout { - send_log "\n\n***\nDid not receive in time\n\n" - exit 2 + send_log "\nMarker not found.\n\n" + exit 1 + } eof { + send_log "Unexpected end of file." + exit 2 } } -expect { - "Starting ovirt-early:" {send_log "\n\n***\nGot ovirt-early marker\n\n"} - timeout {send_log "\n\n***\nDid not receive in time\n\n" - exit 3} -} -expect { - "Starting ovirt:" {send_log "\n\n***\nGot ovirt marker\n\n"} - timeout {send_log "\n\n***\nDid not receive in time\n\n" - exit 4} + +send_log "\n\nUnexpected end of interaction.\n\n" +exit 3' + result=$? + + destroy_node $nodename + stop_networking $IFACE_NAME true + + return $result } + +add_test "test_stateful_pxe" +test_stateful_pxe () { + local nodename="${vm_prefix}-stateful-pxe" + local workdir=$(mktemp -d) + local ipaddress=${NODE_ADDRESS} + + for var in nodename workdir ipaddress; do + eval debug "::\$$var: $var" + done + + start_networking $nodename $IFACE_NAME false true $workdir + + configure_node "${nodename}" "network" "" "10000" "" "local noapic=true" + boot_with_pxe "${nodename}" "ovirt_standalone ovirt_init=/dev/vda ovirt_local_boot ip=${ipaddress}" ${workdir} + + # verify the booting and installation + expect -c ' +set timeout 120 +log_file -noappend stateful-pxe.log + +spawn sudo virsh console '"${nodename}"' + expect { - "Starting ovirt-post:" {send_log "\n\n***\nGot ovirt-post marker\n\n"} - timeout {send_log "\n\n***\nDid not receive in time\n\n" - exit 5} + -exact "Linux version" { send_log "\n\nMarker 1\n\n"; exp_continue } + -exact "Starting ovirt-early:" { send_log "\n\nMarker 2\n\n"; exp_continue } + -exact "Starting ovirt:" { send_log "\n\nMarker 3\n\n"; exp_continue } + -exact "Starting ovirt-post:" { send_log "\n\nMarker 4\n\n"; exp_continue } + -exact "Starting ovirt-firstpost:" { send_log "\n\nMarker 5\n\n"; exp_continue } + -exact "Starting partitioning of /dev/vda" { send_log "\n\nMarker 6\n\n"; exp_continue } + -exact "Restarting system" { send_log "\n\nMarker 7\n\n"; exit } + timeout { + send_log "\nMarker not found.\n\n" + exit 1 + } eof { + send_log "Unexpected end of file." + exit 2 + } } -expect { - "Starting ovirt-firstboot:" {send_log "\n\n***\nGot ovirt-firstboot marker\n\n"} - timeout {send_log "\n\n***\nDid not receive in time\n\n" - exit 6} -}' - sudo bash -c "/usr/bin/expect -c '${script}' < ${port}" +send_log "\n\nUnexpected end of interaction.\n\n" +exit 3' result=$? - printf "result=${result}\n" -} -# Verify that a stateful node has booted properly. -# $1 - the node's name -# $2 - the logfile for recording the transcript -verify_pxeboot_stateful_standalone () { - local nodename=$1 - local port=$(sudo virsh ttyconsole $nodename) - local logfile=$2 - - # leverage the existing stateless test - verify_pxeboot_stateless_standalone $nodename - log "Verifying ${nodename} is booted correctly" - local script=' -log_file -noappend '"${logfile}"' -set timeout 180 + # only continue if we're in a good state + if [ $result -eq 0 ]; then + destroy_node "${nodename}" false + substitute_boot_device "${nodename}" "network" "hd" + boot_from_hd "${nodename}" + + expect -c ' +set timeout 120 +log_file stateful-pxe.log + +send_log "Restarted node, booting from hard disk.\n" + +spawn sudo virsh console '"${nodename}"' + expect { - -re "login:$" {send_log "\n\n***\nGot login prompt!\n\n"} - timeout {send_log "\n\n***\nDid not receive in time\n\n" - exit 7} -}' - sudo bash -c "/usr/bin/expect -c '${script}' < ${port}" + -re "localhost.*login:" { send_log "\n\nLogin marker found\n\n"; exit } + + timeout { + send_log "\nMarker not found.\n\n" + exit 1 + } eof { + send_log "Unexpected end of file." + exit 2 + } } -# TEST: Performs a PXE boot of the node as a standalone, stateless instance. -test_pxeboot_stateless_standalone () { - local nodename="pxe_stateless_standalone-$$" - local hdfile=$(mktemp) +send_log "\n\nUnexpected end of interaction.\n\n" - log "TEST: Booting a stateless standalone node via PXE." - create_hard_disk $hdfile "10G" - pxeboot_node_vm $nodename $OVIRT_NODE_IMAGE_ISO "${hdfile}" "524288" \ - $IFACE_NAME "ovirt_standalone OVIRT_FIRSTBOOT=no" \ - "verify_pxeboot_stateless_standalone $nodename 'pxeboot_stateless_standalone.log'" -} +exit 3 +' + + expect -c ' +set timeout 3 +log_file stateful-pxe.log + +spawn ping -c 3 '"${ipaddress}"' -# TEST: Performs a PXE boot of the node as a standalone instance. The node then performs a full install -test_pxeboot_stateful_standalone () { - local nodename="pxe_stateful_standalone-$$" - local hdfile=$(mktemp) +expect { + -exact "64 bytes from '"${ipaddress}"'" { send_log "\n\nGot ping response!\n"; send_log "\n\nNetworking verified!\n"; exit } - log "TEST: Installing a stateful standalone node via PXE." - create_hard_disk $hdfile "10G" - pxeboot_node_vm $nodename $OVIRT_NODE_IMAGE_ISO "${hdfile}" "524288" \ - $IFACE_NAME "ovirt_standalone OVIRT_FIRSTBOOT=no ovirt_init=/dev/vda" \ - "verify_pxeboot_stateful_standalone $nodename 'pxeboot_stateful_standalone.log'" + timeout { + send_log "\nMarker not found.\n\n" + exit 1 + } eof { + send_log "Unexpected end of file." + exit 2 + } } -# TEST: Performs a CDROM boot of the node as a standalone, stateless instance -test_cdrom_stateless_standalone () { - local nodename="stateless_cdrom_standalone-$$" +send_log "\n\nUnexpected end of interaction.\n\n" + +exit 3' + + result=$? + fi + + destroy_node $nodename + stop_networking $IFACE_NAME true + + return $result - log "TEST: Booting a stateless node from CDROM." - cdrom_boot $nodename "$IFACE_NAME" "$TFTP_ROOT_DIR" "$OVIRT_NODE_IMAGE_ISO" } -# automated testing entry points -{ +# configures the environment for testing +setup_for_testing () { + debug "isofile=${isofile}" + debug "isoname=${isoname}" IFACE_NAME=testbr$$ + debug "IFACE_NAME=${IFACE_NAME}" NETWORK=192.168.$(echo "scale=0; print $$ % 255" | bc -l) + debug "NETWORK=${NETWORK}" NODE_ADDRESS=$NETWORK.100 + debug "NODE_ADDRESS=${NODE_ADDRESS}" DNSMASQ_PID=0 +} + +# cleans up any loose ends +cleanup_after_testing () { + stop_dnsmasq + stop_networking + # destroy any running vms + vm_list=$(sudo virsh list --all | awk '/'${vm_prefix}-'/ { print $2 }') + test -n "$vm_list" && for vm in $vm_list; do + destroy_node $vm + done +} + +# check commandline options +test='' +debugging=false +isofile="${PWD}/ovirt-node-image.iso" +show_viewer=false +vm_prefix="$$" + +while getopts di:n:vwh c; do + case $c in + d) debugging=true;; + i) isofile=($OPTARG);; + n) tests=($OPTARG);; + v) set -v;; + w) show_viewer=true;; + h) usage; exit 0;; + '?') die "invalid option \`-$OPTARG'";; + :) die "missing argument to \`-$OPTARG' option";; + *) die "internal error";; + esac +done + +isoname=$(basename $isofile) +isofile="$(cd `dirname $isofile`; pwd)/${isoname}" + +shift $(($OPTIND - 1)) + +set +u +if [ $# -gt 0 -a -n "$1" ]; then RESULTS=$1; else RESULTS=autotest.log; fi +set -u + +log "Logging results to file: ${RESULTS}" +{ + setup_for_testing + + log "Begin Testing: ${isoname}" - log "Starting tests" - log "Using network: ${NETWORK}.0" + for test in ${tests[@]}; do + execute_test $test + done - test_pxeboot_stateless_standalone - test_pxeboot_stateful_standalone + log "End Testing: RHEV-H" } | sudo tee --append $RESULTS -- 1.6.0.6