#! /usr/bin/env bash # vim: set filetype=sh ts=4 sw=4 sts=4 et: set -e basedir=$(readlink -f "$(dirname "$0")"/../../..) # shellcheck source=lib/shell/colors.inc . "$basedir"/lib/shell/colors.inc namespace=the-bastion-test target="$1" shift || true # all remaining options will be passed as-is on the target docker, through target_role.sh to launch-tests-on-instance.sh get_supported_targets() { local target targets subtarget for dockerfile in "$(dirname "$0")"/../../../docker/Dockerfile.*; do if grep -q '^# TESTOPT ' "$dockerfile"; then target=$(basename "$dockerfile") target=${target/Dockerfile./} # if the file has a TESTFROM entry, then it's actually multiple similar targets if grep -q '^# TESTFROM ' "$dockerfile"; then # shellcheck disable=SC2013 for testfrom in $(grep '^# TESTFROM ' "$dockerfile" | cut -d' ' -f3-); do subtarget="$target@$testfrom" targets="$targets $subtarget" done else targets="$targets $target" fi fi done # shellcheck disable=SC2086 echo $targets } print_supported_targets() { local target for target in $(get_supported_targets | tr " " "\n" | sort); do echo "- $target" done echo } if [ -z "$target" ] || [ "$target" = "--list-targets" ]; then if [ -z "$target" ]; then echo "Usage: $0 [additional options]" echo echo "Supported targets are: " print_supported_targets echo "These additional options are passed directly to the worker:" "$basedir"/tests/functional/launch_tests_on_instance.sh --help-light exit 1 else # shellcheck disable=SC2086 print_supported_targets exit 0 fi fi if echo "$target" | grep -q '@'; then subtarget=$(echo "$target" | cut -d@ -f2) target_dockerfile=$(echo "$target" | cut -d@ -f1) else subtarget='' target_dockerfile="$target" fi target_dockerfile="$(dirname "$0")"/../../../docker/Dockerfile."$target_dockerfile" if [ ! -f "$target_dockerfile" ] ; then echo "Couldn't find a Dockerfile for $target ($target_dockerfile)" >&2 exit 1 fi # build test env echo "Building test environment" testenv_dockerfile="$(dirname "$0")/../../../docker/Dockerfile.tester" docker build -f "$testenv_dockerfile" -t "$namespace:tester" "$(dirname "$0")"/../../.. # if we have a subtarget, we need to override the FROM of the target_dockerfile # don't do this in place however, create a tempfile for this if [ -n "$subtarget" ]; then dockerfiletmp=$(mktemp) trap 'rm -f $dockerfiletmp' EXIT sed -re "s=^FROM .+=FROM $subtarget=" "$target_dockerfile" > "$dockerfiletmp" target_dockerfile="$dockerfiletmp" fi # build target echo "Building target environment" target=$(echo "$target" | sed -re 's/[^a-zA-Z0-9_-]/_/g') docker build -f "$target_dockerfile" -t "$namespace:$target" "$(dirname "$0")"/../../.. # get the target environment we want from the dockerfile testopts="$(grep '^# TESTOPT' "$target_dockerfile" | tail -n1 | cut -c10-)" privileged='' if grep -q '^# PRIVILEGED' "$target_dockerfile"; then privileged='--privileged' fi # cleanup the dockerfile temp if applicable if [ -n "$subtarget" ]; then rm -f "$dockerfiletmp" trap - EXIT fi # create temp key echo "Create user and root SSH keys" privdir=$(mktemp -d) trap 'rm -rf "$privdir"' EXIT ssh-keygen -t ecdsa -N '' -q -f "$privdir"/userkey USER_PRIVKEY_B64=$(base64 -w0 < "$privdir"/userkey) USER_PUBKEY_B64=$(base64 -w0 < "$privdir"/userkey.pub) ssh-keygen -t ecdsa -N '' -q -f "$privdir"/rootkey ROOT_PRIVKEY_B64=$(base64 -w0 < "$privdir"/rootkey) ROOT_PUBKEY_B64=$(base64 -w0 < "$privdir"/rootkey.pub) rm -rf "$privdir" trap - EXIT echo "Configuring network" docker rm -f "bastion_${target}_target" 2>/dev/null || true docker rm -f "bastion_${target}_tester" 2>/dev/null || true if docker inspect "bastion-$target" >/dev/null 2>&1; then docker network rm "bastion-$target" >/dev/null fi docker network create "bastion-$target" >/dev/null # run target but force entrypoint to test one, and add some keys in env (will be shared with tester) echo "Starting target instance" docker run $privileged \ --name="bastion_${target}_target" \ --network "bastion-$target" \ -d \ --entrypoint=/opt/bastion/tests/functional/docker/target_role.sh \ -e USER_PUBKEY_B64="$USER_PUBKEY_B64" \ -e ROOT_PUBKEY_B64="$ROOT_PUBKEY_B64" \ -e TARGET_USER="user.5000" \ -e WANT_HTTP_PROXY=1 \ $namespace:"$target" docker logs -f "bastion_${target}_target" | sed -u -e 's/^/target: /;s/$/\r/' & show_target_logs() { if [ "$ret" -ne 0 ] && [ "$ret" -ne 255 ]; then echo echo '>>> TARGET LOGS FOLLOW <<<' docker logs "bastion_${target}_target" | sed -u -e 's/^/target: /;s/$/\r/' fi } cleanup() { set +e docker rm -f "bastion_${target}_target" "bastion_${target}_tester" >/dev/null 2>/dev/null || true docker network rm "bastion-$target" >/dev/null } cleanup_exit() { show_target_logs cleanup } cleanup_int() { printf "%b%b%b\\n" "$WHITE_ON_RED" '>>> CLEANING UP, DO NOT CTRL+C AGAIN! <<<' "$NOC" cleanup } trap "cleanup_int" INT HUP # run test env on it if [[ -t 1 ]] && [ -z "$DOCKER_TTY" ]; then DOCKER_TTY="true" else DOCKER_TTY="false" fi echo "Starting test instance and run tests with --tty=$DOCKER_TTY (testopts: $testopts, extra params: $*)" set +e # shellcheck disable=SC2086 docker run \ --name="bastion_${target}_tester" \ --network "bastion-$target" \ -i \ --tty=$DOCKER_TTY \ -e TARGET_IP="bastion_${target}_target" \ -e TARGET_PORT=22 \ -e TARGET_PROXY_PORT=8443 \ -e TARGET_USER="user.5000" \ -e USER_PRIVKEY_B64="$USER_PRIVKEY_B64" \ -e ROOT_PRIVKEY_B64="$ROOT_PRIVKEY_B64" \ -e EXTRA_OPTIONS="$testopts $*" \ $namespace:tester ret=$? if [ $ret -ne 0 ]; then printf '%b%b%b\n' "$WHITE_ON_RED" "Test instance returned $ret" "$NOC" fi trap - INT HUP show_target_logs if [ $ret -ne 0 ]; then if [ $ret -eq 255 ]; then printf '%b%b%b\n' "$WHITE_ON_RED" "=====================================" "$NOC" printf '%b%b%b\n' "$WHITE_ON_RED" ">>> TARGET DIDN'T START CORRECTLY <<<" "$NOC" printf '%b%b%b\n' "$WHITE_ON_RED" "=====================================" "$NOC" docker logs "bastion_${target}_target" elif [ $ret -eq 254 ]; then printf '%b%b%b\n' "$WHITE_ON_RED" "============================" "$NOC" printf '%b%b%b\n' "$WHITE_ON_RED" ">>> PREREQUISITES FAILED <<<" "$NOC" printf '%b%b%b\n' "$WHITE_ON_RED" "============================" "$NOC" docker logs "bastion_${target}_tester" else printf '%b%b%b\n' "$WHITE_ON_RED" "==============================================" "$NOC" printf '%b%b%b\n' "$WHITE_ON_RED" ">>> AN OVERVIEW OF THE FAILED TESTS FOLLOW <<<" "$NOC" printf '%b%b%b\n' "$WHITE_ON_RED" "==============================================" "$NOC" docker logs "bastion_${target}_tester" | grep -B5 -F -- '[FAIL]' | grep -vF -- '[ OK ]' echo "=== last few lines of the tester logs follow:" docker logs "bastion_${target}_tester" | tail -7 fi fi cleanup exit $ret