Files
infix/test/env
T

278 lines
6.5 KiB
Bash
Executable File

#!/bin/sh
set -e
testdir=$(dirname "$(readlink -f "$0")")
. "$testdir/.env"
usage()
{
cat <<EOF
usage: test/env [-cDhiKr] -f <IMAGE> -q <QENETH-DIR> <COMMAND> [<ARGS>...]
test/env [-cDhiKr] -C -t <TOPOLOGY> <COMMAND> [<ARGS>...]
Run <COMMAND> in a pre-packaged container with all the packages
required for running the test suite installed.
Options:
-b <BASE-DIR>
Use this directory as the top-level bind mount inside the container.
If not specified, Infix's top directory is used.
-c
Clean up cruft, lingering images, old containers, unused volumes.
Used by GitHub action to prevent issues with running tests.
-C
Don't containerize the command, run it directly in the current
namespaces
-D
Prefer Docker over podman. This is implied when -t is specified,
as podman does not allow the necessary network permissions to be
granted to the container
-f <IMAGE>
Specify images required for test, squashfs image is required
if testing with kernel. bios and disk image is required if
testing with bios.
-h
Show this help message
-i
Interactive mode, e.g., 'make test-sh'
-K
Even if /dev/kvm is usable, do not map it the container. This is
useful to see how tests will run in a CI setting, where KVM is
typically not available
-p <BUNDLE>
Infix RAUC bundle to use for upgrade tests.
-q <QENETH-DIR>
Directory containing a topology.dot.in, suitable for consumption
by qeneth. A copy of this network is created, and launched. The
resulting topology is used as the default physical topology when
running tests
-r
Use random container names instead of "infamyN". Useful for the
unit tests running in CI environments which may see occasional
name clashes for "infamy0" due to race conditions.
-t <TOPOLOGY>
Rather than starting a qeneth network, attach to this existing
topology. If the command is containerized, it will be launched
in the host's network namespace
EOF
}
get_base_img()
{
local files="$1"
local base_img_file
base_img_file=$(echo "$files" | tr ' ' '\n' | grep -- '-disk.qcow2$')
echo "$envdir/qeneth/$(basename "$base_img_file")"
}
start_topology()
{
qenethdir="$1"
files="$*"
[ "$files" ] || { true && return; }
[ "$qenethdir" ] || { true && return; }
rm -rf "$envdir/qeneth"
cp -a "$qenethdir" "$envdir/qeneth"
# Map files in to qeneth
for f in $files; do
filename="$(basename "$f")"
file=$(readlink -f "$f")
ln -sf "$file" "$envdir/qeneth/$filename"
done
base_img=$(get_base_img "$files")
test_img_name="${base_img%-disk.qcow2}-disk-test"
base_img_name="${base_img%-disk.qcow2}-disk"
test_img_raw="${test_img_name}.img"
base_img_raw="${base_img_name}.img"
test_img_qcow2="${test_img_name}.qcow2"
qemu-img convert -f qcow2 -O raw "$base_img" "$base_img_raw"
$testdir/inject-test-mode -b "$base_img_raw" -o "$test_img_raw"
qemu-img convert -f raw -O qcow2 "$test_img_raw" "$test_img_qcow2"
img_name=$(basename $test_img_qcow2)
sed -i "s/qn_image=\".*\"/qn_image=\"$img_name\"/" "$envdir/qeneth/topology.dot.in"
(cd "$envdir/qeneth/" && $qeneth generate && $qeneth start)
INFAMY_ARGS="$INFAMY_ARGS $envdir/qeneth/topology.dot"
cat <<EOF >"$envdir/bin/qeneth"
#!/bin/sh
cd $envdir/qeneth && exec $testdir/qeneth/qeneth "\$@"
EOF
chmod +x "$envdir/bin/qeneth"
}
name()
{
nm=infamy
id=0
if [ -n "$random" ]; then
# Let podman/docker allocate random hostname and container name
return
fi
names=$($(runner) ps -f name='infamy.*' --format '{{.Names}}')
while true; do
name="$nm$id"
unset hit
for n in $names; do
if [ "$name" = "$n" ]; then
hit=true
break;
fi
done
if [ -n "$hit" ]; then
id=$((id + 1))
continue
fi
break;
done
echo "--hostname $name --name $name"
}
# Global options
containerize=yes
[ -c /dev/kvm ] && kvm="--device=/dev/kvm"
files=
basedir="$ixdir"
while getopts "b:cCDf:hiKp:q:rt:" opt; do
case ${opt} in
b)
basedir="$OPTARG"
;;
c)
$(runner) image prune -af
$(runner) volume prune -f
$(runner) container prune -f
exit 0
;;
C)
containerize=
;;
D)
runners="docker podman"
;;
f)
files="$files $OPTARG"
;;
h)
usage && exit 0
;;
i)
interactive=--interactive
;;
K)
kvm=
;;
p)
INFAMY_ARGS="$INFAMY_ARGS -p $OPTARG"
;;
q)
qenethdir="$OPTARG"
network="--sysctl net.ipv6.conf.all.disable_ipv6=0"
;;
r)
random=true
;;
t)
topology="$OPTARG"
network="--network host --volume $topology:$topology:ro"
runners="docker podman"
;;
*)
>&2 echo "Unknown option -$opt"
usage
exit 1
;;
esac
done
if [ "$containerize" ]; then
volumes="--volume $basedir:$basedir --workdir=$ixdir/test"
case "$(runner)" in
docker)
volumes="$volumes --env HOST_CHOWN_PATH=$ixdir/test"
volumes="$volumes --env HOST_CHOWN_UID=$(id -u)"
volumes="$volumes --env HOST_CHOWN_GID=$(id -g)"
;;
podman)
;;
esac
mkdir -p "$HOME/.infix"
touch "$HOME/.infix/.ash_history"
# shellcheck disable=SC2016,SC2046,SC2086,SC2119
exec $(runner) run \
--cap-add=NET_RAW \
--cap-add=NET_ADMIN \
--device=/dev/net/tun \
--env PYTHONHASHSEED=${PYTHONHASHSEED:-$(shuf -i 0-$(((1 << 32) - 1)) -n 1)} \
--env VIRTUAL_ENV_DISABLE_PROMPT=yes \
--env INFAMY_ARGS="$INFAMY_ARGS" \
--env INFAMY_EXTRA_ARGS="$INFAMY_EXTRA_ARGS" \
--env PROMPT_DIRTRIM="$ixdir" \
--env NINEPM_PROJ_CONFIG="$NINEPM_PROJ_CONFIG" \
--env QENETH_PATH="$testdir/templates:$testdir" \
--env PS1="$(build_ps1)" \
$extra_env \
--expose 9001-9010 --publish-all \
-v "$HOME/.infix/.ash_history":/root/.ash_history \
$(name) \
$interactive \
--rm \
--security-opt seccomp=unconfined \
$network \
--tty \
$volumes \
$kvm \
$INFIX_TEST \
"$0" -C "$@"
else
if [ ! -f ~/.9pm.rc ]; then
cat <<-EOF >~/.9pm.rc
# Generated by Infix env
SSH_OPTS: "-o StrictHostKeyChecking=no"
LOG_PATH: "$logdir"
EOF
fi
fi
shift $((OPTIND - 1))
if [ $# -lt 1 ]; then
usage && exit 1
fi
# shellcheck disable=SC1091
. "$envdir/bin/activate"
export PYTHONPATH="$testdir"
INFAMY_ARGS="$INFAMY_ARGS -y $envdir/yangdir"
start_topology "$qenethdir" "$files"
[ "$topology" ] && INFAMY_ARGS="$INFAMY_ARGS $topology"
export INFAMY_ARGS
if [ -n "$INFAMY_EXTRA_ARGS" ]; then
exec "$@" -o="$INFAMY_EXTRA_ARGS"
fi
exec "$@"