Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

guest-test framework improvement and add 6 TDX guest BAT TCs #156

Merged
merged 11 commits into from
Dec 28, 2023
Merged
29 changes: 17 additions & 12 deletions guest-test/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ No multi-VMs test scenarios covered/supported.

In any case of issue debugging, please refer to above test log with VM QEMU config info and launch VM and debug issues manually running test scripts/binaries.

A prepared Guest OS Image (qcow2 or raw image format) is requried with preset root account and password, several values/parameters in qemu.config.json highly depend on Guest OS Image, please accomodate accordingly.
A prepared Guest OS Image (qcow2 or raw image format) is requried with preset root account and password, several values/parameters in common.json highly depend on Guest OS Image, please accomodate accordingly.

## Usage
### common.json and qemu.config.json description
Expand Down Expand Up @@ -46,11 +46,11 @@ group "common" includes all configurable values to be passed to group "vm", "tdx
group "vm" includes all legacy vm launch qemu config options, which can be used to launch legacy vm standalone or as base part to launch tdx vm

group "vm" 2nd-level-keys could be bypassed if not provided (file not exists)
"cfg_var_6" & "cfg_var_10"
"cfg_var_6", "cfg_var_10" could be bypassed separately, "cfg_var_5" & "cfg_var_9" could be bypassed in pair

group "tdx" includes tdx vm specific qemu config options, which is used to launch tdx vm (with group "vm" as base) or as a based part to launch tdxio vm

group "tdxio" includes tdxio vm specific qemu config options, which is used to launch tdxio vm (with group "vm" + "tdx" as base)
group "tdxio" includes tdxio/tdx-connect vm specific qemu config options, which is used to launch tdxio/tdx-connect vm (with group "vm" + "tdx" as base)

note about qemu.config.json:
- no changes allowed on 1st-level-keys hierarchy
Expand All @@ -64,14 +64,17 @@ main test entrance, with following key args can be passed to override the values
- `-m` $MEM memory size in GB
- `-d` $DEBUG debug on/off
- `-t` $VM_TYPE vm_type legacy/tdx/tdxio
- `-f` $FEATURE feature sub-folder for new feature vm test extension
- `-x` $TESTCASE testcase pass to test_executor
- `-c` $CMDLINE guest kernel extra commandline
- `-p` $PMU guest pmu off/on
- `-g` $GCOV code coverage test mode off/on
- `-i` $JSON_C file path under guest-test to standalone common.json file
- `-j` $JSON_Q file path under guest-test to standalone qemu.config.json file

above key args will be recorded in a fresh new test_params.py for further import/source purpose accross scripts
above key args will be recorded in a fresh new test_params.py for further import/source purpose accross python and shell scripts

by enter each test, qemu_get_config.py will be called to get following pre-set parameters from qemu.config.json
by enter each test, qemu_get_config.py will be called to get following pre-set parameters from common.json
- $KERNEL_IMG values passed by group "common" key "kernel_img"
- $INITRD_IMG values passed by group "common" key "initrd_img"
- $BIOS_IMG values passed by group "common" key "bios_img"
Expand All @@ -82,9 +85,9 @@ by enter each test, qemu_get_config.py will be called to get following pre-set p
- $SSHPASS values passed by group "common" key "guest_root_passwd"

call guest.qemu_runner.sh and wait for $BOOT_PATTERN (shows VM boot up completed and ready for login) during VM boot
- $BOOT_PATTERN selected based on following CentOS Stream 8/9 boot log example: "*Kernel*on*x86_64*"
- $BOOT_PATTERN is selected based on following CentOS Stream 8/9 boot log example: "*Kernel*on*an*x86_64*"

boot log quoted:
boot log example quoted:
```
CentOS Stream 9
Kernel 6.5.0-rc5-next-20230809-next-20230809 on an x86_64
Expand All @@ -100,12 +103,12 @@ if $ERR_STRx found, handle the error info accordingly (err_handlers)

no matter what, in the end, pkill VM process to avoid any potential test step failures above

Note: bydeault, $GCOV is off, if $GCOV is on, above VM life-cycles management logic will be bypassed to keep VM process alive for gcov code coverage data collection
Note: by deault, $GCOV is off, if $GCOV is on, above VM life-cycles management logic will be bypassed to keep VM process alive for gcov code coverage data collection

### guest.qemu_runner description
VM boot engine, with parames exported from qemu_get_config.py and test scenario config sourced from test_params.py

before VM boot, for $VM_TYPE tdx or tdxio, tdx_pre_check will be called to make sure basic environment is ready for TDX/TDXIO launching
before VM boot, for $VM_TYPE tdx or tdxio, tdx_pre_check and tdx_module_check will be called to make sure basic environment is ready for TDX/TDXIO launching

VM boot is triggered by qemu_runner.py based on $VM_TYPE, with proper qemu config options applied

Expand All @@ -117,8 +120,10 @@ guest VM test execution basic framework implemented in guerst.test_executor.sh,
- guest_test_close, function based on sshpass to close VM

## How to add new feature test
as described above, if simply add new TCs to run based on current qemu.config.json format, just need to implement it in test_executor with new $TESTCASE branch,
as described above, if simply add new TCs to run based on current common.json and qemu.config.json format, just need to implement it in $FEATURE.test_executor.sh under guest-test/$FEATURE subfolder,
please leverage reference code "common variables example" and "common works example" in tdx/tdx.test_executor.sh, further implement "$FEATURE specific Functions" and "$FEATURE specific code path",
common functions of guest.test_executor.sh should be good enough to prepare/run/close new $FEATURE specific tests implemented in $FEATURE.test_executor.sh;

common functions of test_executor should be good enough to prepare/run/close new $TESTCASE
it's allowed to customize and pass $FEATURE standalone common.json and qemu.config.json, please refer to ### common.json and qemu.config.json description and ### guest.test_launcher description for quick rule reference

if qemu.config.json format will be revised due to feature changes on QEMU implementation, please update qemu.config.json and qemu_get_config.py accordingly
furthermore, if common.json and qemu.config.json format will be revised due to feature changes on QEMU implementation, please update qemu_get_config.py accordingly
46 changes: 45 additions & 1 deletion guest-test/guest.qemu_runner.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,49 @@ SCRIPT_DIR="$( cd "$( dirname "$0" )" && pwd )"
echo "$SCRIPT_DIR"

###################### Functions ######################
# function to remove 0x and prefix useless 0 for hex data
version_check() {
local version_raw=$1
if [[ "$version_raw" = "0x00000000" ]]; then
local version=0x0
else
local version_hex
version_hex=${version_raw#0x}
version_hex=${version_hex##+(0)}
local version=$((16#$version_hex))
fi
echo "$version"
}

# function to do tdx module status and version check
tdx_module_check() {
local tdx_module_path="/sys/firmware/tdx/tdx_module/"
local status
local attributes
local vendor_id
local major_version
local minor_version
local build_date
local build_num
status=$(cat "$tdx_module_path"status)
[[ "$status" = "initialized" ]] || \
die "TDX module not initialized correctly, \
please check host kernel tdx enabling setup."
test_print_trc "TDX module initialized correctly"
attributes=$(cat "$tdx_module_path"attributes)
attributes=$(version_check "$attributes")
vendor_id=$(cat "$tdx_module_path"vendor_id)
major_version=$(cat "$tdx_module_path"major_version)
major_version=$(version_check "$major_version")
minor_version=$(cat "$tdx_module_path"minor_version)
minor_version=$(version_check "$minor_version")
build_date=$(cat "$tdx_module_path"build_date)
build_num=$(cat "$tdx_module_path"build_num)
build_num=$(version_check "$build_num")
test_print_trc "TDX module: attributes $attributes, vendor_id $vendor_id, \
major_version $major_version, minor_version $minor_version, \
build_date $build_date, build_num $build_num"
}

# function to do TDX/TDXIO VM launching basic pre-check
# list all the variables value
Expand Down Expand Up @@ -81,8 +124,9 @@ source "$SCRIPT_DIR"/test_params.py
# do basic pre-check for TDX/TDXIO VM launching
if [[ $VM_TYPE == "tdx" ]] || [[ $VM_TYPE == "tdxio" ]]; then
tdx_pre_check
tdx_module_check
fi

# launch VM by qemu via qemu_runner.py
test_print_trc "qemu_runner start to launch $VM_TYPE VM"
python3 "$SCRIPT_DIR"/qemu_runner.py
python3 "$SCRIPT_DIR"/qemu_runner.py
21 changes: 12 additions & 9 deletions guest-test/guest.test_executor.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,16 @@ EOF
source $GUEST_TEST_DIR/common.sh
cd $GUEST_TEST_DIR
cd $1
dnf list installed gcc || dnf install -y gcc || \
{ die "Failed to install gcc in guest os"; return 1; }
dnf list installed glibc-static || dnf install -y glibc-static || \
{ die "Failed to install glibc-static in guest os"; return 1; }
make || { die "Failed to compile source code $1"; return 1; }
dnf list installed gcc || dnf install -y gcc > /dev/null 2>&1
dnf list installed glibc-static || dnf install -y glibc-static > /dev/null 2>&1
apt list installed gcc | grep "installed" || apt-get install -y gcc > /dev/null 2>&1
apt list installed libc6-dev | grep "installed" || apt-get install -y libc6-dev > /dev/null 2>&1
make || die "Failed to compile source code $1"
if [ -f $2 ]; then
chmod a+x $2
cp $2 $GUEST_TEST_DIR
else
die "Can't find test binary $2"
return 1
fi
EOF
ERR_NUM=$?
Expand Down Expand Up @@ -90,14 +89,18 @@ guest_test_close() {
sshpass -e ssh -p "$PORT" -o StrictHostKeyChecking=no root@localhost << EOF
source $GUEST_TEST_DIR/common.sh
test_print_trc "guest test complete, close VM now"
systemctl reboot --reboot-argument=now
if [[ "$VM_TYPE" = "legacy" ]]; then
shutdown now
else
systemctl reboot --reboot-argument=now
fi
EOF
ERR_NUM=$?
if [ $ERR_NUM -eq 0 ]; then
test_print_trc "Guest VM closed properly after test"
return 0
else
return 1
die "Failed on close guest VM"
fi
}

Expand All @@ -114,5 +117,5 @@ if [ "${BASH_SOURCE[0]}" -ef "$0" ]; then
cd "$SCRIPT_DIR" || die "fail to switch to $SCRIPT_DIR"
# select specific "$FEATURE.test_executor.sh" by $FEATURE
"$FEATURE"/"$FEATURE".test_executor.sh || \
{ die "Failed on $TESTCASE of $FEATURE"; return 1; }
die "Failed on $TESTCASE of $FEATURE"
fi
21 changes: 14 additions & 7 deletions guest-test/guest.test_launcher.sh
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,14 @@ guest_kernel_check() {
EOF
}

guest_kernel_reboot() {
guest_kernel_shutdown() {
sshpass -e ssh -p "$PORT" -o StrictHostKeyChecking=no root@localhost << EOF
systemctl reboot --reboot-argument=now
echo "$VM_TYPE VM guest kernel shutdown now"
if [[ "$VM_TYPE" = "legacy" ]]; then
shutdown now
else
systemctl reboot --reboot-argument=now
fi
EOF
}

Expand Down Expand Up @@ -251,7 +256,9 @@ while read -r line; do
fi
done < <(
if [ "$GCOV" == "off" ]; then
timeout "$TIMEOUT" ./guest.qemu_runner.sh
# keep timeout process run foreground for direct script execution correctness
# handle timeout effect case SIGTERM impact on terminal no type-in prompt issue
timeout --foreground "$TIMEOUT" ./guest.qemu_runner.sh || reset
else
test_print_trc "${VM_TYPE}vm_$PORT keep alive for gcov data collection" && ./guest.qemu_runner.sh
fi
Expand Down Expand Up @@ -308,17 +315,17 @@ if ! guest_kernel_check; then
pkill "${VM_TYPE}vm_$PORT"
die "$VM_TYPE VM test seems fail at beginning, please check test log"
fi
# guest_kernel_kernel function zero return value shows TDVM is still accessible handling
# handling: no matter why it's still accessible, close it by guest_kernel_reboot function
# guest_kernel_check function zero return value shows TDVM is still accessible handling
# handling: no matter why it's still accessible, close it by guest_kernel_shutdown function
elif [ "$GCOV" == "off" ]; then
if ! guest_kernel_reboot; then
if guest_kernel_shutdown; then
test_print_trc "$VM_TYPE VM is still up"
test_print_trc "time: $SECONDS"
test_print_trc "SSHPASS: $SSHPASS"
test_print_trc "PORT: $PORT"
test_print_trc "$VM_TYPE VM closed"
# must die here since TDVM should be closed and not accessible if test complete all correctly
# else it's due to test die before reaching final close point td_test_close function
# else it's due to test die before reaching final close point guest_test_close function
die "$VM_TYPE VM test fail, please check test log"
fi
else # [ $GCOV == "on" ] || [ guest_kernel_check return 0 ]
Expand Down
2 changes: 1 addition & 1 deletion guest-test/qemu.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"cfg_var_6": "-initrd $INITRD_IMG ",
"cfg_var_7": "-netdev user,id=mynet0,hostfwd=tcp::$PORT-:22 ",
"cfg_var_8": "-drive file=$GUEST_IMG,if=virtio,format=$IMG_FORMAT ",
"cfg_var_9": "-append \"root=/dev/vda3 ro console=hvc0 earlyprintk=ttyS0 ignore_loglevel debug earlyprintk l1tf=off initcall_debug log_buf_len=200M nokaslr tsc=reliable efi=debug mce=off efi=debug $CMDLINE\" ",
"cfg_var_9": "-append \"root=/dev/vda3 ro console=hvc0 earlyprintk=ttyS0 ignore_loglevel debug earlyprintk l1tf=off initcall_debug log_buf_len=200M nokaslr tsc=reliable efi=debug mce=off $CMDLINE\" ",
"cfg_var_10": "-bios $BIOS_IMG ",
"cfg_var_11": "-monitor telnet:127.0.0.1:$PORT_TEL,server,nowait "
},
Expand Down
5 changes: 4 additions & 1 deletion guest-test/qemu_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import subprocess as sp
from qemu_get_config import *
from test_params import *
from signal import signal, SIGPIPE, SIG_DFL

###################### Variables ######################
# all variables imported from qemu_get_config and test_params
Expand All @@ -25,6 +26,8 @@
# all work done in qemu_get_config.py

###################### Do Works ######################
# igore SIGPIPE in case of broken pipe errno 32 case
signal(SIGPIPE, SIG_DFL)
# launch legacy common vm based on vm_type config
if vm_type == "legacy":
command = '{} {}'.format(qemu_img, vm_cfg)
Expand All @@ -38,4 +41,4 @@
# launch tdxio vm based on vm_type config
if vm_type == "tdxio":
command = '{} {} {} {}'.format(qemu_img, vm_cfg, tdx_cfg, tdxio_cfg)
sp.run(command, shell=True)
sp.run(command, shell=True)
Loading