Skip to content

Commit ec38b21

Browse files
[qemu] Use ssh to run tests inside of qemu machine (#1292)
Summary: QEMU tests now start a qemu instance in the background and then SSH into the machine to run tests. This makes the logs much cleaner and also enables running interactively in a normal terminal instead of a serial console. Type of change: /kind test-infra Test Plan: Tested that `bazel test --config=qemu-bpf //...` works (apart from a flake in stirling error bpf test that I'll address separately). Signed-off-by: James Bartlett <jamesbartlett@pixielabs.ai>
1 parent 3afa56a commit ec38b21

8 files changed

Lines changed: 149 additions & 53 deletions

File tree

bazel/cc_toolchains/sysroots/sysroots.bzl

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,44 +19,44 @@ load("//bazel/cc_toolchains:utils.bzl", "abi")
1919

2020
SYSROOT_LOCATIONS = dict(
2121
sysroot_x86_64_glibc2_36_runtime = dict(
22-
sha256 = "7dcdec4bd693329a1ed670a87e95814a87f0906bd0f0c14058f47003b9fcf52a",
22+
sha256 = "4fe3499357bca3e6ac8f6b6fb0266849eb434e0bbc95f2cfeeaa2dce7fe3913a",
2323
strip_prefix = "",
24-
urls = ["https://storage.googleapis.com/pixie-dev-public/sysroots/pl6/sysroot-amd64-runtime.tar.gz"],
24+
urls = ["https://storage.googleapis.com/pixie-dev-public/sysroots/pl7/sysroot-amd64-runtime.tar.gz"],
2525
),
2626
sysroot_x86_64_glibc2_36_build = dict(
27-
sha256 = "b3c7cd7044ba3de0f3550bece6e21f69eb198e9a165eeab690257a749fe442d0",
27+
sha256 = "0aace63714ccf25a894c5ce02cbe19fd77ac04c804aeb1edbf14e3acf803d552",
2828
strip_prefix = "",
29-
urls = ["https://storage.googleapis.com/pixie-dev-public/sysroots/pl6/sysroot-amd64-build.tar.gz"],
29+
urls = ["https://storage.googleapis.com/pixie-dev-public/sysroots/pl7/sysroot-amd64-build.tar.gz"],
3030
),
3131
sysroot_x86_64_glibc2_36_test = dict(
32-
sha256 = "bee652932886a34bbd5bd9ea3a3c52c08f462c005faa0e2353297dd5b9070989",
32+
sha256 = "d324655373e8f4f4eb234bec60061b034c1efa476dc4321dda54b403013eb183",
3333
strip_prefix = "",
34-
urls = ["https://storage.googleapis.com/pixie-dev-public/sysroots/pl6/sysroot-amd64-test.tar.gz"],
34+
urls = ["https://storage.googleapis.com/pixie-dev-public/sysroots/pl7/sysroot-amd64-test.tar.gz"],
3535
),
3636
sysroot_x86_64_glibc2_36_debug = dict(
37-
sha256 = "5639c73b5afd7c16bbdcbfcbd54262ea232283a5f5b4852e51c77062dea62f2e",
37+
sha256 = "1430be9aa4290060c45f2afddeef59460746ccea91435605ce3d6fe907f6a558",
3838
strip_prefix = "",
39-
urls = ["https://storage.googleapis.com/pixie-dev-public/sysroots/pl6/sysroot-amd64-debug.tar.gz"],
39+
urls = ["https://storage.googleapis.com/pixie-dev-public/sysroots/pl7/sysroot-amd64-debug.tar.gz"],
4040
),
4141
sysroot_aarch64_glibc2_36_runtime = dict(
42-
sha256 = "48ea0856326974dca562db5a4e7ef09befef50fdb7a13698966e06393a3b090c",
42+
sha256 = "a7584932a57b9cc5cce8ddd81437d53af6ab9407499c12a3a75231ed8d63195d",
4343
strip_prefix = "",
44-
urls = ["https://storage.googleapis.com/pixie-dev-public/sysroots/pl6/sysroot-arm64-runtime.tar.gz"],
44+
urls = ["https://storage.googleapis.com/pixie-dev-public/sysroots/pl7/sysroot-arm64-runtime.tar.gz"],
4545
),
4646
sysroot_aarch64_glibc2_36_build = dict(
47-
sha256 = "304e86332754e473938d5614a12e8676fb36481096ab6915b7d667faa0373a74",
47+
sha256 = "86fdedb79870366363916507700dffb84eb1ebf1e94decb12fad17e2d568455f",
4848
strip_prefix = "",
49-
urls = ["https://storage.googleapis.com/pixie-dev-public/sysroots/pl6/sysroot-arm64-build.tar.gz"],
49+
urls = ["https://storage.googleapis.com/pixie-dev-public/sysroots/pl7/sysroot-arm64-build.tar.gz"],
5050
),
5151
sysroot_aarch64_glibc2_36_test = dict(
52-
sha256 = "12be586d2562e1ed49e4ea5c178c8df73c596c522b75b9b1de1700e081c6fd1e",
52+
sha256 = "8f51888a333544737086960fa49e212e65aa8c10624a0e92bd2c521f82c49c81",
5353
strip_prefix = "",
54-
urls = ["https://storage.googleapis.com/pixie-dev-public/sysroots/pl6/sysroot-arm64-test.tar.gz"],
54+
urls = ["https://storage.googleapis.com/pixie-dev-public/sysroots/pl7/sysroot-arm64-test.tar.gz"],
5555
),
5656
sysroot_aarch64_glibc2_36_debug = dict(
57-
sha256 = "4cb30d6f9e73f66a03ba34a74fb51171ac7d45365102c41db2add0b852c7db33",
57+
sha256 = "96df14385ad58a61cc3dd921c8b5830451da2fedbd421b0ef5ebb6c3fb82554f",
5858
strip_prefix = "",
59-
urls = ["https://storage.googleapis.com/pixie-dev-public/sysroots/pl6/sysroot-arm64-debug.tar.gz"],
59+
urls = ["https://storage.googleapis.com/pixie-dev-public/sysroots/pl7/sysroot-arm64-debug.tar.gz"],
6060
),
6161
)
6262

bazel/test_runners/qemu_with_kernel/init

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ function mount_system_dirs() {
7575

7676
mkdir -p /dev/shm
7777
mount -t tmpfs tmpfs /dev/shm
78+
79+
mkdir -p /dev/pts
80+
mount -t devpts devpts /dev/pts
7881
}
7982

8083
function mount_test_fs() {
@@ -83,6 +86,12 @@ function mount_test_fs() {
8386
mount -t 9p -o trans=virtio test_fs /test_fs || true
8487
}
8588

89+
function setup_eth0() {
90+
ip link set dev eth0 up
91+
ifconfig eth0 10.0.2.15 netmask 255.255.255.0
92+
route add default gw 10.0.2.2
93+
}
94+
8695
function setup_networking() {
8796
ip link set dev lo up
8897

@@ -103,7 +112,8 @@ ff02::2 ip6-allrouters
103112
ff02::3 ip6-allhosts
104113
105114
EOF
106-
fi
115+
fi
116+
setup_eth0
107117
}
108118

109119
function setup_containers() {
@@ -166,9 +176,9 @@ Welcome to PX BPF Runner
166176
167177
EOF
168178

169-
test_runner="/test_fs/test_runner_inside_qemu.sh"
170-
if [[ -x "${test_runner}" ]]; then
171-
exec /bin/bash -c "${test_runner}"
179+
run_sshd="/test_fs/run_sshd.sh"
180+
if [[ -x "${run_sshd}" ]]; then
181+
exec /bin/bash -c "${run_sshd}"
172182
else
173183
exec /bin/exit_qemu_with_status 3
174184
fi

bazel/test_runners/qemu_with_kernel/launcher.sh

Lines changed: 78 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,22 @@ set -e
1919

2020
KERNEL_IMAGE=%kernelimage%
2121
DISK_IMAGE=%diskimage%
22-
BAZEL_QEMU_TEST_RUNNER_PATH=%testrunnerinsideqemu%
22+
BAZEL_RUN_SSHD_PATH=%runsshd%
2323
RUN_QEMU_SCRIPT=%runqemuscript%
2424

2525
# Create a tmp directory that serves as the /test_fs sanbox dir inside qemu.
2626
tmpdir_for_sandbox=$(mktemp -d)
2727

28+
# shellcheck disable=SC2317
2829
function cleanup {
2930
retval=$?
3031
rm -rf "${tmpdir_for_sandbox:?}" || true
32+
33+
if [[ -n "${qemu_pid}" ]]; then
34+
kill "${qemu_pid}" &> /dev/null || true
35+
wait "${qemu_pid}" || true
36+
qemu_pid=""
37+
fi
3138
exit "${retval}"
3239
}
3340

@@ -56,6 +63,10 @@ function path_qemu_sandbox() {
5663
echo "$v"
5764
}
5865

66+
function qemu_is_running() {
67+
kill -0 "${qemu_pid}" &> /dev/null
68+
}
69+
5970

6071
# We need to write and transform the environment variables so that they have the "correct"
6172
# paths when run inside of qemu.
@@ -104,34 +115,89 @@ qemu_warnings_file=$(strip_pwd_from_path "${TEST_WARNINGS_OUTPUT_FILE}")
104115
qemu_testlogs_dir="${qemu_warnings_file/${qemu_warnings_file##*/testlogs/}}"
105116
cp -afL "${testlogs_dir}/" "${tmpdir_for_sandbox}/${qemu_testlogs_dir}/"
106117

107-
# Copy the test runner and test cmd into the sandbox.
108-
test_runner_file="${tmpdir_for_sandbox}/test_runner_inside_qemu.sh"
118+
# Create test tmp dir.
119+
if [[ -n "${TEST_TMPDIR}" ]]; then
120+
mkdir -p "$(path_qemu_sandbox "${TEST_TMPDIR}")"
121+
fi
122+
123+
# Copy the test cmd into the sandbox.
109124
test_base=${PWD//"${OLDPWD}"/\/test_fs}
110125
test_cmd_path="${tmpdir_for_sandbox}/test_cmd.sh"
111126
test_cmd_path_in_qemu="/test_fs/test_cmd.sh"
112127

113-
echo "#!/bin/bash -e" > "${test_cmd_path}"
114-
echo "${@:1}" >> "${test_cmd_path}"
128+
cat <<EOF > "${test_cmd_path}"
129+
#!/bin/bash -e
130+
source /test_fs/test_env.sh
131+
cd ${test_base}
132+
export TESTING_UNDER_QEMU=true
133+
${@:1}
134+
EOF
115135
chmod +x "${test_cmd_path}"
116136

117137
printf "export test_base=%s\n" "${test_base}" >> "${test_env_file}"
118138
printf "export test_exec_path=%s\n" "${test_cmd_path_in_qemu}" >> "${test_env_file}"
119139

120-
cp -afL "${BAZEL_QEMU_TEST_RUNNER_PATH}" "${test_runner_file}"
140+
# Setup ssh.
141+
ssh_priv_key="${tmpdir_for_sandbox}/ssh_key"
142+
ssh_pub_key_inside_qemu="/test_fs/ssh_key.pub"
143+
ssh-keygen -f "${ssh_priv_key}" -N '' -b 1024 > /dev/null
121144

122-
# Launch the qemu test.
123-
retval=0
124-
(exec env - \
145+
ssh_env_file="${tmpdir_for_sandbox}/ssh_env.sh"
146+
echo "#!/bin/bash" > "${ssh_env_file}"
147+
echo "export SSH_PUB_KEY=${ssh_pub_key_inside_qemu}" >> "${ssh_env_file}"
148+
149+
run_sshd_file="${tmpdir_for_sandbox}/run_sshd.sh"
150+
cp -afL "${BAZEL_RUN_SSHD_PATH}" "${run_sshd_file}"
151+
152+
monitor_sock="mon.sock"
153+
# Launch qemu.
154+
env - \
125155
QEMU_TEST_FS_PATH="${tmpdir_for_sandbox}" \
126156
QEMU_KERNEL_IMAGE="${KERNEL_IMAGE}" \
127157
QEMU_DISK_BASE_RO="${PWD}/${DISK_IMAGE}" \
128-
"${RUN_QEMU_SCRIPT}" ) || retval=$?
158+
MONITOR_SOCK="${monitor_sock}" \
159+
"${RUN_QEMU_SCRIPT}" &> "qemu.log" &
160+
qemu_pid="$!"
161+
162+
echo "QEMU logs available at: $(pwd)/qemu.log"
163+
echo "QEMU monitor available at unix socket: $(pwd)/${monitor_sock}"
164+
165+
166+
echo 'Waiting for QEMU to boot'
167+
while qemu_is_running && ! echo "info usernet" | netcat -NU "${monitor_sock}" &> /dev/null; do
168+
sleep 1
169+
done
170+
171+
host_ssh_port="$(echo "info usernet" | netcat -NU "${monitor_sock}" | grep "HOST_FORWARD" | awk '{print $4}')"
172+
ssh_opts=(
173+
-q
174+
-i "${ssh_priv_key}"
175+
-o "StrictHostKeyChecking=no"
176+
-o "UserKnownHostsFile=/dev/null"
177+
-p "${host_ssh_port}"
178+
root@localhost
179+
)
180+
181+
# Wait for qemu to boot and ssh to be ready
182+
echo 'Waiting for SSH to come online'
183+
while qemu_is_running && ! ssh "${ssh_opts[@]}" 'echo test' &> /dev/null; do
184+
sleep 1
185+
done
186+
187+
if ! qemu_is_running; then
188+
echo 'QEMU failed to boot'
189+
cat -v qemu.log
190+
echo "Log available in sandbox at: $(pwd)/qemu.log"
191+
exit 3
192+
fi
193+
194+
retval=0
195+
ssh "${ssh_opts[@]}" '/bin/bash -c '"${test_cmd_path_in_qemu}" || retval=$?
129196

130197
# We use a known path to find the testlogs directory so that we can copy the results back from qemu.
131198
testlogs_dir="${TEST_WARNINGS_OUTPUT_FILE%%/testlogs/*}/testlogs/"
132199
qemu_warnings_file=$(strip_pwd_from_path "${TEST_WARNINGS_OUTPUT_FILE}")
133200
qemu_testlogs_dir="${qemu_warnings_file/${qemu_warnings_file##*/testlogs/}}"
134-
135201
cp -afL "${tmpdir_for_sandbox}/${qemu_testlogs_dir}/" "${testlogs_dir}/"
136202

137-
exit $retval
203+
exit "${retval}"

bazel/test_runners/qemu_with_kernel/run_qemu.sh

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ function check_env_set() {
2727
check_env_set QEMU_TEST_FS_PATH
2828
check_env_set QEMU_KERNEL_IMAGE
2929
check_env_set QEMU_DISK_BASE_RO
30+
check_env_set MONITOR_SOCK
3031

3132
QEMU_MEMORY=${QEMU_MEMORY:-4096M}
3233
QEMU_CPU_COUNT=${QEMU_CPU_COUNT:-1}
@@ -76,16 +77,25 @@ flags+=(-append "console=ttyS0 root=/dev/sda")
7677
# Disable graphics mode.
7778
flags+=(-nographic)
7879

80+
# Enable ssh port forwarding.
81+
flags+=(-device "virtio-net-pci,netdev=net0")
82+
flags+=(-netdev "user,id=net0,hostfwd=tcp::0-:22")
83+
84+
flags+=(-monitor "unix:${MONITOR_SOCK},server,nowait")
85+
7986
retval=0
8087
qemu-system-x86_64 "${flags[@]}" || retval=$?
8188

8289
if [[ "${retval}" -gt 0 ]]; then
8390
if [[ "${retval}" -lt 128 ]]; then
84-
echo "QEMU failed to launch with status code: ${retval}"
91+
echo "QEMU failed to launch with status code: ${retval}"
8592
else
86-
retval="$(echo "($retval-128-1)/2" | bc)"
87-
echo "Test failed with status: ${retval}"
93+
retval="$(echo "($retval-128-1)/2" | bc)"
8894
fi
8995
fi
9096

97+
if [[ "${retval}" -ne 0 ]]; then
98+
echo "Running sshd inside qemu failed with status: ${retval}"
99+
fi
100+
91101
exit "${retval}"

bazel/test_runners/qemu_with_kernel/test_runner_inside_qemu.sh renamed to bazel/test_runners/qemu_with_kernel/run_sshd.sh

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,27 @@ function finish {
2525
trap finish EXIT
2626
trap finish ERR
2727

28+
function check_env_set() {
29+
if [[ -z "${!1}" ]]; then
30+
echo "The environment variable \"$1\" needs to be set"
31+
exit 1
32+
fi
33+
}
34+
2835
# This file is generated by the test launcher.
2936
# shellcheck disable=SC1091
30-
source /test_fs/test_env.sh
31-
32-
cd "${test_base:?}"
37+
source /test_fs/ssh_env.sh
3338

34-
if [[ -n "${GTEST_TMP_DIR}" ]]; then
35-
mkdir -p "${GTEST_TMP_DIR}"
36-
fi
39+
check_env_set SSH_PUB_KEY
3740

38-
export TESTING_UNDER_QEMU=true
41+
mkdir -p "/etc/ssh"
42+
echo "PermitRootLogin without-password" >> /etc/ssh/sshd_config
43+
mkdir -p "/root/.ssh"
44+
cat "${SSH_PUB_KEY}" >> /root/.ssh/authorized_keys
45+
ssh-keygen -A -N '' -b 1024 &> /dev/null
46+
useradd sshd
47+
mkdir -p "/run/sshd"
48+
mkdir -p "/var/log"
3949

40-
# Actually run the test and capture the return value.
41-
retval=0
42-
"${test_exec_path:?}" || retval=$?
43-
exit $retval
50+
echo "Starting SSH Daemon"
51+
exec /usr/sbin/sshd -p 22 -e -D

bazel/test_runners/qemu_with_kernel/runner.bzl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,15 @@ def _test_runner_impl(ctx):
6060
"%diskimage%": "bazel/test_runners/qemu_with_kernel/disk_image.qcow2",
6161
"%kernelimage%": "bazel/test_runners/qemu_with_kernel/bzImage",
6262
"%runqemuscript%": "bazel/test_runners/qemu_with_kernel/run_qemu.sh",
63-
"%testrunnerinsideqemu%": "bazel/test_runners/qemu_with_kernel/test_runner_inside_qemu.sh",
63+
"%runsshd%": "bazel/test_runners/qemu_with_kernel/run_sshd.sh",
6464
},
6565
is_executable = True,
6666
)
6767

6868
runfiles = ctx.runfiles(files = [
6969
disk_image,
7070
kernel_bzimage,
71-
ctx.files._test_runner_inside_qemu[0],
71+
ctx.files._run_sshd[0],
7272
ctx.files._run_qemu_script[0],
7373
])
7474

@@ -108,12 +108,12 @@ qemu_with_kernel_test_runner = rule(
108108
default = Label("//bazel/test_runners/qemu_with_kernel:run_qemu.sh"),
109109
allow_single_file = True,
110110
),
111-
"_test_launcher_tpl": attr.label(
112-
default = Label("//bazel/test_runners/qemu_with_kernel:launcher.sh"),
111+
"_run_sshd": attr.label(
112+
default = Label("//bazel/test_runners/qemu_with_kernel:run_sshd.sh"),
113113
allow_single_file = True,
114114
),
115-
"_test_runner_inside_qemu": attr.label(
116-
default = Label("//bazel/test_runners/qemu_with_kernel:test_runner_inside_qemu.sh"),
115+
"_test_launcher_tpl": attr.label(
116+
default = Label("//bazel/test_runners/qemu_with_kernel:launcher.sh"),
117117
allow_single_file = True,
118118
),
119119
},

tools/docker/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ GRAALVM_ARCHIVE_FNAME := graalvm-native-image-22.3.0.tar.gz
5050
GRAALVM_ARCHIVE_GS_PATH := gs://pixie-dev-public/graalvm-native-image-22.3.0-$(GRAALVM_IMAGE_VERSION).tar.gz
5151

5252
## Sysroot parameters
53-
SYSROOT_REV := pl6
53+
SYSROOT_REV := pl7
5454
SYSROOT_BUILD_DIR := $(BUILD_DIR)/sysroots
5555
SYSROOT_ARCHITECTURES := amd64 arm64
5656
SYSROOT_VARIANTS := runtime build test

tools/docker/sysroot_creator/package_groups/test.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@ include:
2323
- aardvark-dns
2424
- netavark
2525
- podman
26+
# ssh is used to run qemu tests
27+
- openssh-server

0 commit comments

Comments
 (0)