mirror of
https://github.com/netdata/libbpf.git
synced 2026-04-06 00:29:07 +08:00
vmtest: use libguestfs for disk image manipulations
Running vmtest inside a container removes the ability to use certain root powers, among other things - mounting arbitrary images. Use libguestfs in order to avoid having to mount anything. Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
This commit is contained in:
committed by
Andrii Nakryiko
parent
3b1714aa92
commit
1987a34fc9
2
.github/actions/setup/action.yml
vendored
2
.github/actions/setup/action.yml
vendored
@@ -12,7 +12,7 @@ runs:
|
|||||||
echo 'echo ::group::Env setup' > /tmp/ci_setup
|
echo 'echo ::group::Env setup' > /tmp/ci_setup
|
||||||
echo export DEBIAN_FRONTEND=noninteractive >> /tmp/ci_setup
|
echo export DEBIAN_FRONTEND=noninteractive >> /tmp/ci_setup
|
||||||
echo sudo apt-get update >> /tmp/ci_setup
|
echo sudo apt-get update >> /tmp/ci_setup
|
||||||
echo sudo apt-get install -y aptitude qemu-kvm zstd binutils-dev elfutils libcap-dev libelf-dev libdw-dev >> /tmp/ci_setup
|
echo sudo apt-get install -y aptitude qemu-kvm zstd binutils-dev elfutils libcap-dev libelf-dev libdw-dev libguestfs-tools >> /tmp/ci_setup
|
||||||
echo export PROJECT_NAME='libbpf' >> /tmp/ci_setup
|
echo export PROJECT_NAME='libbpf' >> /tmp/ci_setup
|
||||||
echo export AUTHOR_EMAIL="$(git log -1 --pretty=\"%aE\")" >> /tmp/ci_setup
|
echo export AUTHOR_EMAIL="$(git log -1 --pretty=\"%aE\")" >> /tmp/ci_setup
|
||||||
echo export REPO_ROOT=$GITHUB_WORKSPACE >> /tmp/ci_setup
|
echo export REPO_ROOT=$GITHUB_WORKSPACE >> /tmp/ci_setup
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ Run "${PROJECT_NAME}" tests in a virtual machine.
|
|||||||
This exits with status 0 on success, 1 if the virtual machine ran successfully
|
This exits with status 0 on success, 1 if the virtual machine ran successfully
|
||||||
but tests failed, and 2 if we encountered a fatal error.
|
but tests failed, and 2 if we encountered a fatal error.
|
||||||
|
|
||||||
This script uses sudo to mount and modify the disk image.
|
This script uses sudo to work around a libguestfs bug.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
IMG path of virtual machine disk image to create
|
IMG path of virtual machine disk image to create
|
||||||
@@ -177,6 +177,11 @@ else
|
|||||||
fi
|
fi
|
||||||
IMG="${!OPTIND}"
|
IMG="${!OPTIND}"
|
||||||
fi
|
fi
|
||||||
|
if [[ "${SOURCE_FULLCOPY}" == "1" ]]; then
|
||||||
|
img_size=2G
|
||||||
|
else
|
||||||
|
img_size=8G
|
||||||
|
fi
|
||||||
|
|
||||||
unset URLS
|
unset URLS
|
||||||
cache_urls() {
|
cache_urls() {
|
||||||
@@ -242,15 +247,29 @@ cp_img() {
|
|||||||
create_rootfs_img() {
|
create_rootfs_img() {
|
||||||
local path="$1"
|
local path="$1"
|
||||||
set_nocow "$path"
|
set_nocow "$path"
|
||||||
truncate -s 2G "$path"
|
truncate -s "$img_size" "$path"
|
||||||
mkfs.ext4 -q "$path"
|
mkfs.ext4 -q "$path"
|
||||||
}
|
}
|
||||||
|
|
||||||
download_rootfs() {
|
download_rootfs() {
|
||||||
local rootfsversion="$1"
|
local rootfsversion="$1"
|
||||||
local dir="$2"
|
|
||||||
download "${ARCH}/${PROJECT_NAME}-vmtest-rootfs-$rootfsversion.tar.zst" |
|
download "${ARCH}/${PROJECT_NAME}-vmtest-rootfs-$rootfsversion.tar.zst" |
|
||||||
zstd -d | sudo tar -C "$dir" -x
|
zstd -d
|
||||||
|
}
|
||||||
|
|
||||||
|
tar_in() {
|
||||||
|
local dst_path="$1"
|
||||||
|
# guestfish --remote does not forward file descriptors, which prevents
|
||||||
|
# us from using `tar-in -` or bash process substitution. We don't want
|
||||||
|
# to copy all the data into a temporary file, so use a FIFO.
|
||||||
|
tmp=$(mktemp -d)
|
||||||
|
mkfifo "$tmp/fifo"
|
||||||
|
cat >"$tmp/fifo" &
|
||||||
|
local cat_pid=$!
|
||||||
|
guestfish --remote tar-in "$tmp/fifo" "$dst_path"
|
||||||
|
wait "$cat_pid"
|
||||||
|
rm -r "$tmp"
|
||||||
|
tmp=
|
||||||
}
|
}
|
||||||
|
|
||||||
if (( LIST )); then
|
if (( LIST )); then
|
||||||
@@ -297,18 +316,12 @@ echo "Disk image: $IMG" >&2
|
|||||||
tmp=
|
tmp=
|
||||||
ARCH_DIR="$DIR/$ARCH"
|
ARCH_DIR="$DIR/$ARCH"
|
||||||
mkdir -p "$ARCH_DIR"
|
mkdir -p "$ARCH_DIR"
|
||||||
mnt="$(mktemp -d -p "$DIR" mnt.XXXXXXXXXX)"
|
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
if [[ -n $tmp ]]; then
|
if [[ -n $tmp ]]; then
|
||||||
rm -f "$tmp" || true
|
rm -rf "$tmp" || true
|
||||||
fi
|
|
||||||
if mountpoint -q "$mnt"; then
|
|
||||||
sudo umount "$mnt" || true
|
|
||||||
fi
|
|
||||||
if [[ -d "$mnt" ]]; then
|
|
||||||
rmdir "$mnt" || true
|
|
||||||
fi
|
fi
|
||||||
|
guestfish --remote exit 2>/dev/null || true
|
||||||
}
|
}
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
|
|
||||||
@@ -324,12 +337,19 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Mount and set up the rootfs image.
|
# Mount and set up the rootfs image. Use a persistent guestfish session in
|
||||||
|
# order to avoid the startup overhead.
|
||||||
|
# Work around https://bugs.launchpad.net/fuel/+bug/1467579.
|
||||||
|
sudo chmod +r /boot/vmlinuz*
|
||||||
|
eval "$(guestfish --listen)"
|
||||||
if (( ONESHOT )); then
|
if (( ONESHOT )); then
|
||||||
rm -f "$IMG"
|
rm -f "$IMG"
|
||||||
create_rootfs_img "$IMG"
|
create_rootfs_img "$IMG"
|
||||||
sudo mount -o loop "$IMG" "$mnt"
|
guestfish --remote \
|
||||||
download_rootfs "$ROOTFSVERSION" "$mnt"
|
add "$IMG" label:img : \
|
||||||
|
launch : \
|
||||||
|
mount /dev/disk/guestfs/img /
|
||||||
|
download_rootfs "$ROOTFSVERSION" | tar_in /
|
||||||
else
|
else
|
||||||
if (( ! SKIPIMG )); then
|
if (( ! SKIPIMG )); then
|
||||||
rootfs_img="${ARCH_DIR}/${PROJECT_NAME}-vmtest-rootfs-${ROOTFSVERSION}.img"
|
rootfs_img="${ARCH_DIR}/${PROJECT_NAME}-vmtest-rootfs-${ROOTFSVERSION}.img"
|
||||||
@@ -337,13 +357,15 @@ else
|
|||||||
if [[ ! -e $rootfs_img ]]; then
|
if [[ ! -e $rootfs_img ]]; then
|
||||||
tmp="$(mktemp "$rootfs_img.XXX.part")"
|
tmp="$(mktemp "$rootfs_img.XXX.part")"
|
||||||
set_nocow "$tmp"
|
set_nocow "$tmp"
|
||||||
truncate -s 2G "$tmp"
|
truncate -s "$img_size" "$tmp"
|
||||||
mkfs.ext4 -q "$tmp"
|
mkfs.ext4 -q "$tmp"
|
||||||
sudo mount -o loop "$tmp" "$mnt"
|
|
||||||
|
|
||||||
download_rootfs "$ROOTFSVERSION" "$mnt"
|
# libguestfs supports hotplugging only with a libvirt
|
||||||
|
# backend, which we are not using here, so handle the
|
||||||
|
# temporary image in a separate session.
|
||||||
|
download_rootfs "$ROOTFSVERSION" |
|
||||||
|
guestfish -a "$tmp" tar-in - /
|
||||||
|
|
||||||
sudo umount "$mnt"
|
|
||||||
mv "$tmp" "$rootfs_img"
|
mv "$tmp" "$rootfs_img"
|
||||||
tmp=
|
tmp=
|
||||||
fi
|
fi
|
||||||
@@ -351,11 +373,14 @@ else
|
|||||||
rm -f "$IMG"
|
rm -f "$IMG"
|
||||||
cp_img "$rootfs_img" "$IMG"
|
cp_img "$rootfs_img" "$IMG"
|
||||||
fi
|
fi
|
||||||
sudo mount -o loop "$IMG" "$mnt"
|
guestfish --remote \
|
||||||
|
add "$IMG" label:img : \
|
||||||
|
launch : \
|
||||||
|
mount /dev/disk/guestfs/img /
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Install vmlinux.
|
# Install vmlinux.
|
||||||
vmlinux="$mnt/boot/vmlinux-${KERNELRELEASE}"
|
vmlinux="/boot/vmlinux-${KERNELRELEASE}"
|
||||||
if [[ -v BUILDDIR || $ONESHOT -eq 0 ]]; then
|
if [[ -v BUILDDIR || $ONESHOT -eq 0 ]]; then
|
||||||
if [[ -v BUILDDIR ]]; then
|
if [[ -v BUILDDIR ]]; then
|
||||||
source_vmlinux="${BUILDDIR}/vmlinux"
|
source_vmlinux="${BUILDDIR}/vmlinux"
|
||||||
@@ -368,15 +393,14 @@ if [[ -v BUILDDIR || $ONESHOT -eq 0 ]]; then
|
|||||||
tmp=
|
tmp=
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
echo "Copying vmlinux..." >&2
|
|
||||||
sudo rsync -cp --chmod 0644 "$source_vmlinux" "$vmlinux"
|
|
||||||
else
|
else
|
||||||
# We could use "sudo zstd -o", but let's not run zstd as root with
|
source_vmlinux="${ARCH_DIR}/vmlinux-${KERNELRELEASE}"
|
||||||
# input from the internet.
|
download "${ARCH}/vmlinux-${KERNELRELEASE}.zst" | zstd -d >"$source_vmlinux"
|
||||||
download "${ARCH}/vmlinux-${KERNELRELEASE}.zst" |
|
|
||||||
zstd -d | sudo tee "$vmlinux" > /dev/null
|
|
||||||
sudo chmod 644 "$vmlinux"
|
|
||||||
fi
|
fi
|
||||||
|
echo "Copying vmlinux..." >&2
|
||||||
|
guestfish --remote \
|
||||||
|
upload "$source_vmlinux" "$vmlinux" : \
|
||||||
|
chmod 644 "$vmlinux"
|
||||||
|
|
||||||
travis_fold end vmlinux_setup
|
travis_fold end vmlinux_setup
|
||||||
|
|
||||||
@@ -384,7 +408,7 @@ REPO_PATH="${SELFTEST_REPO_PATH:-travis-ci/vmtest/bpf-next}"
|
|||||||
LIBBPF_PATH="${REPO_ROOT}" \
|
LIBBPF_PATH="${REPO_ROOT}" \
|
||||||
VMTEST_ROOT="${VMTEST_ROOT}" \
|
VMTEST_ROOT="${VMTEST_ROOT}" \
|
||||||
REPO_PATH="${REPO_PATH}" \
|
REPO_PATH="${REPO_PATH}" \
|
||||||
VMLINUX_BTF=${vmlinux} ${VMTEST_ROOT}/build_selftests.sh
|
VMLINUX_BTF=$(realpath ${source_vmlinux}) ${VMTEST_ROOT}/build_selftests.sh
|
||||||
|
|
||||||
travis_fold start bpftool_checks "Running bpftool checks..."
|
travis_fold start bpftool_checks "Running bpftool checks..."
|
||||||
if [[ "${KERNEL}" = 'LATEST' ]]; then
|
if [[ "${KERNEL}" = 'LATEST' ]]; then
|
||||||
@@ -402,23 +426,31 @@ if (( SKIPSOURCE )); then
|
|||||||
else
|
else
|
||||||
echo "Copying source files..." >&2
|
echo "Copying source files..." >&2
|
||||||
# Copy the source files in.
|
# Copy the source files in.
|
||||||
sudo mkdir -p -m 0755 "$mnt/${PROJECT_NAME}"
|
guestfish --remote \
|
||||||
|
mkdir-p "/${PROJECT_NAME}" : \
|
||||||
|
chmod 0755 "/${PROJECT_NAME}"
|
||||||
if [[ "${SOURCE_FULLCOPY}" == "1" ]]; then
|
if [[ "${SOURCE_FULLCOPY}" == "1" ]]; then
|
||||||
git ls-files -z | sudo rsync --files-from=- -0cpt . "$mnt/${PROJECT_NAME}"
|
git ls-files -z | tar --null --files-from=- -c | tar_in "/${PROJECT_NAME}"
|
||||||
else
|
else
|
||||||
sudo mkdir -p -m 0755 ${mnt}/${PROJECT_NAME}/{selftests,travis-ci}
|
guestfish --remote \
|
||||||
|
mkdir-p "/${PROJECT_NAME}/selftests" : \
|
||||||
|
chmod 0755 "/${PROJECT_NAME}/selftests" : \
|
||||||
|
mkdir-p "/${PROJECT_NAME}/travis-ci" : \
|
||||||
|
chmod 0755 "/${PROJECT_NAME}/travis-ci"
|
||||||
tree --du -shaC "${REPO_ROOT}/selftests/bpf"
|
tree --du -shaC "${REPO_ROOT}/selftests/bpf"
|
||||||
sudo rsync -avm "${REPO_ROOT}/selftests/bpf" "$mnt/${PROJECT_NAME}/selftests/"
|
tar -C "${REPO_ROOT}/selftests" -c bpf | tar_in "/${PROJECT_NAME}/selftests"
|
||||||
sudo rsync -avm "${REPO_ROOT}/travis-ci/vmtest" "$mnt/${PROJECT_NAME}/travis-ci/"
|
tar -C "${REPO_ROOT}/travis-ci" -c vmtest | tar_in "/${PROJECT_NAME}/travis-ci"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
setup_script="#!/bin/sh
|
tmp=$(mktemp)
|
||||||
|
cat <<HERE >"$tmp"
|
||||||
|
"#!/bin/sh
|
||||||
|
|
||||||
echo 'Skipping setup commands'
|
echo 'Skipping setup commands'
|
||||||
echo 0 > /exitstatus
|
echo 0 > /exitstatus
|
||||||
chmod 644 /exitstatus"
|
chmod 644 /exitstatus
|
||||||
|
HERE
|
||||||
|
|
||||||
# Create the init scripts.
|
# Create the init scripts.
|
||||||
if [[ ! -z SETUPCMD ]]; then
|
if [[ ! -z SETUPCMD ]]; then
|
||||||
@@ -427,30 +459,38 @@ if [[ ! -z SETUPCMD ]]; then
|
|||||||
kernel="${KERNELRELEASE}"
|
kernel="${KERNELRELEASE}"
|
||||||
if [[ -v BUILDDIR ]]; then kernel='latest'; fi
|
if [[ -v BUILDDIR ]]; then kernel='latest'; fi
|
||||||
setup_envvars="export KERNEL=${kernel}"
|
setup_envvars="export KERNEL=${kernel}"
|
||||||
setup_script=$(printf "#!/bin/sh
|
cat <<HERE >"$tmp"
|
||||||
|
#!/bin/sh
|
||||||
set -eux
|
set -eux
|
||||||
|
|
||||||
echo 'Running setup commands'
|
echo 'Running setup commands'
|
||||||
%s
|
${setup_envvars}
|
||||||
set +e; %s; exitstatus=\$?; set -e
|
set +e; ${setup_cmd}; exitstatus=\$?; set -e
|
||||||
echo \$exitstatus > /exitstatus
|
echo \$exitstatus > /exitstatus
|
||||||
chmod 644 /exitstatus" "${setup_envvars}" "${setup_cmd}")
|
chmod 644 /exitstatus
|
||||||
|
HERE
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "${setup_script}" | sudo tee "$mnt/etc/rcS.d/S50-run-tests" > /dev/null
|
guestfish --remote \
|
||||||
sudo chmod 755 "$mnt/etc/rcS.d/S50-run-tests"
|
upload "$tmp" /etc/rcS.d/S50-run-tests : \
|
||||||
|
chmod 755 /etc/rcS.d/S50-run-tests
|
||||||
|
|
||||||
fold_shutdown="$(travis_fold start shutdown)"
|
fold_shutdown="$(travis_fold start shutdown)"
|
||||||
poweroff_script="#!/bin/sh
|
cat <<HERE >"$tmp"
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
echo ${fold_shutdown}
|
echo ${fold_shutdown}
|
||||||
echo -e '\033[1;33mShutdown\033[0m\n'
|
echo -e '\033[1;33mShutdown\033[0m\n'
|
||||||
|
|
||||||
poweroff"
|
poweroff
|
||||||
echo "${poweroff_script}" | sudo tee "$mnt/etc/rcS.d/S99-poweroff" > /dev/null
|
HERE
|
||||||
sudo chmod 755 "$mnt/etc/rcS.d/S99-poweroff"
|
guestfish --remote \
|
||||||
|
upload "$tmp" /etc/rcS.d/S99-poweroff : \
|
||||||
|
chmod 755 /etc/rcS.d/S99-poweroff
|
||||||
|
rm "$tmp"
|
||||||
|
tmp=
|
||||||
|
|
||||||
sudo umount "$mnt"
|
guestfish --remote exit
|
||||||
|
|
||||||
echo "Starting VM with $(nproc) CPUs..."
|
echo "Starting VM with $(nproc) CPUs..."
|
||||||
|
|
||||||
@@ -480,14 +520,12 @@ esac
|
|||||||
-drive file="$IMG",format=raw,index=1,media=disk,if=virtio,cache=none \
|
-drive file="$IMG",format=raw,index=1,media=disk,if=virtio,cache=none \
|
||||||
-kernel "$vmlinuz" -append "root=/dev/vda rw console=$console kernel.panic=-1 $APPEND"
|
-kernel "$vmlinuz" -append "root=/dev/vda rw console=$console kernel.panic=-1 $APPEND"
|
||||||
|
|
||||||
sudo mount -o loop "$IMG" "$mnt"
|
if exitstatus="$(guestfish --ro -a "$IMG" -i cat /exitstatus 2>/dev/null)"; then
|
||||||
if exitstatus="$(cat "$mnt/exitstatus" 2>/dev/null)"; then
|
|
||||||
printf '\nTests exit status: %s\n' "$exitstatus" >&2
|
printf '\nTests exit status: %s\n' "$exitstatus" >&2
|
||||||
else
|
else
|
||||||
printf '\nCould not read tests exit status\n' >&2
|
printf '\nCould not read tests exit status\n' >&2
|
||||||
exitstatus=1
|
exitstatus=1
|
||||||
fi
|
fi
|
||||||
sudo umount "$mnt"
|
|
||||||
|
|
||||||
travis_fold end shutdown
|
travis_fold end shutdown
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user