scripts/io-tests.sh
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# heimdall-container io-limit kernel tests (crates/heimdall-container/tests/io.rs).
# Heimdall is a defensive sandbox; the jobs only read and write their own files.
#
# They need what scripts/container-tests.sh needs plus the cgroup v2 io
# controller and a disk of their own, so they run in a privileged ROOTFUL
# podman container (rootless podman gets no io controller and no loop
# devices): a fresh 512 MiB loop device with ext2 holds every job dir, bundle
# and file, and HEIMDALL_IO_TEST_DISK names it.
#
# Usage, from the repo root on a Linux host with podman and sudo:
# scripts/io-tests.sh
# Environment: as scripts/container-tests.sh (HEIMDALL_TEST_IMAGE,
# CARGO_TARGET_DIR, CARGO_HOME, CARGO_REGISTRY, HEIMDALL_CONTAINER_TEST_ARGS);
# PODMAN (default "sudo -n podman"). The image must be in root's store
# (scripts/io-tests.sh copies it from the user's store when it is missing).
set -eu
cd "$(dirname "$0")/.."
if [ "${HEIMDALL_IO_INNER:-}" != 1 ]; then
img=${HEIMDALL_TEST_IMAGE:-localhost/nordisk-cargo-toolchain:heim-m0}
pm=${PODMAN:-sudo -n podman}
tgt=${CARGO_TARGET_DIR:-$PWD/target}
mkdir -p "$tgt"
if ! $pm image exists "$img"; then
podman save "$img" | $pm load
fi
extra=""
if [ -n "${CARGO_HOME:-}" ]; then extra="-v $CARGO_HOME:/ch -e CARGO_HOME=/ch"; fi
if [ -n "${CARGO_REGISTRY:-}" ]; then extra="$extra -v $CARGO_REGISTRY:/usr/local/cargo/registry"; fi
rc=0
# shellcheck disable=SC2086
$pm run --rm --privileged --cgroupns=private \
-v "$PWD":/src -v "$tgt":/tgt -e CARGO_TARGET_DIR=/tgt $extra \
-e HEIMDALL_IO_INNER=1 -e HEIMDALL_CONTAINER_TEST_ARGS="${HEIMDALL_CONTAINER_TEST_ARGS:-}" \
${HEIMDALL_CONTAINER_DEBUG:+-e HEIMDALL_CONTAINER_DEBUG=1} -e HOST_UID="$(id -u)" -e HOST_GID="$(id -g)" \
-e CARGO_BUILD_JOBS="${CARGO_BUILD_JOBS:-8}" \
-w /src "$img" scripts/io-tests.sh || rc=$?
exit $rc
fi
# Inside the (rootful) container: clean up the disk and hand the target dir
# back to the caller on exit.
cleanup() {
umount /mnt/hgio 2>/dev/null || true
[ -n "${dev:-}" ] && losetup -d "$dev" 2>/dev/null || true
rm -f /var/tmp/hgio.img
chown -R "$HOST_UID:$HOST_GID" "$CARGO_TARGET_DIR" ${CARGO_HOME:+"$CARGO_HOME"} 2>/dev/null || true
}
trap cleanup EXIT
cg=/sys/fs/cgroup
if [ ! -w "$cg/cgroup.subtree_control" ]; then
echo "cgroup v2 is not writable here (need --privileged and cgroup v2)" >&2
exit 2
fi
mkdir -p "$cg/init"
for p in $(cat "$cg/cgroup.procs"); do echo "$p" > "$cg/init/cgroup.procs" 2>/dev/null || true; done
for c in cpu memory pids io; do
if grep -qw "$c" "$cg/cgroup.controllers"; then
echo "+$c" > "$cg/cgroup.subtree_control"
else
echo "controller $c is not delegated to this container (rootful podman needed)" >&2
exit 2
fi
done
echo "controllers enabled: $(cat "$cg/cgroup.subtree_control")"
# The tests run as the caller's uid, as a service would: Heimdall's parent
# cgroup is delegated to it (owned, controllers on), and the test process
# sits in a leaf of it so it may move job processes into job cgroups.
mkdir -p "$cg/heimdall/runner"
echo "+cpu +memory +pids +io" > "$cg/heimdall/cgroup.subtree_control"
chown -R "$HOST_UID:$HOST_GID" "$cg/heimdall"
truncate -s 512M /var/tmp/hgio.img
dev=$(losetup -f --show /var/tmp/hgio.img)
busybox mke2fs -q "$dev"
mkdir -p /mnt/hgio
mount "$dev" /mnt/hgio
chmod 1777 /mnt/hgio
num=$(cat "/sys/class/block/$(basename "$dev")/dev")
echo "test disk $dev = $num"
chown "$HOST_UID:$HOST_GID" /mnt/hgio
echo $$ > "$cg/heimdall/runner/cgroup.procs"
# shellcheck disable=SC2016
HOME=/tmp HEIMDALL_IO_TEST_DISK="$num" HEIMDALL_PLAIN_SCRATCH=/mnt/hgio \
HEIMDALL_CONTAINER_SHIM="$CARGO_TARGET_DIR/debug/heimdall-container-shim" \
setpriv --reuid "$HOST_UID" --regid "$HOST_GID" --clear-groups sh -c '
cargo build -p nordisk-heimdall-container --features youki --bins &&
cargo test -p nordisk-heimdall-container --features youki --test io -- --ignored --test-threads=1 $HEIMDALL_CONTAINER_TEST_ARGS'