diff --git a/tests/integration/runk/gha-run.sh b/tests/integration/runk/gha-run.sh new file mode 100755 index 0000000000..3f97c63aab --- /dev/null +++ b/tests/integration/runk/gha-run.sh @@ -0,0 +1,59 @@ +#!/bin/bash +# +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +set -o errexit +set -o nounset +set -o pipefail + +kata_tarball_dir="${2:-kata-artifacts}" +runk_dir="$(dirname "$(readlink -f "$0")")" +source "${runk_dir}/../../common.bash" + +function install_dependencies() { + info "Installing the dependencies needed for running the runk tests" + + # Dependency list of projects that we can rely on the system packages + # - jq + declare -a system_deps=( + jq + ) + + sudo apt-get update + sudo apt-get -y install "${system_deps[@]}" + + ensure_yq + + # Dependency list of projects that we can install them + # directly from their releases on GitHub: + # - containerd + # - cri-container-cni release tarball already includes CNI plugins + declare -a github_deps + github_deps[0]="cri_containerd:$(get_from_kata_deps "externals.containerd.${CONTAINERD_VERSION}")" + + for github_dep in "${github_deps[@]}"; do + IFS=":" read -r -a dep <<< "${github_dep}" + install_${dep[0]} "${dep[1]}" + done +} + +function run() { + info "Running runk tests using" + + bash -c ${runk_dir}/runk-tests.sh +} + +function main() { + action="${1:-}" + case "${action}" in + install-dependencies) install_dependencies ;; + install-kata) install_kata ;; + run) run ;; + *) >&2 die "Invalid argument" ;; + esac +} + +main "$@" diff --git a/tests/integration/runk/runk-tests.sh b/tests/integration/runk/runk-tests.sh new file mode 100755 index 0000000000..714f10af50 --- /dev/null +++ b/tests/integration/runk/runk-tests.sh @@ -0,0 +1,99 @@ +#!/bin/bash +# +# Copyright (c) 2023 Kata Contributors +# +# SPDX-License-Identifier: Apache-2.0 +# +# This test will validate runk with containerd + +set -o errexit +set -o nounset +set -o pipefail +set -o errtrace + +tracing_dir="$(dirname "$(readlink -f "$0")")" +source "${tracing_dir}/../../common.bash" +source "${tracing_dir}/../../metrics/lib/common.bash" + +RUNK_BIN_PATH="/usr/local/bin/runk" +TEST_IMAGE="docker.io/library/busybox:latest" +CONTAINER_ID="id1" +PID_FILE="${CONTAINER_ID}.pid" +WORK_DIR="$(mktemp -d --tmpdir runk.XXXXX)" + +setup() { + echo "pull container image" + check_images ${TEST_IMAGE} +} + +test_runk() { + echo "start container with runk" + # Bind mount ${WORK_DIR}:/tmp. Tests below will store files in this dir and check them when container is frozon. + sudo ctr run --pid-file ${PID_FILE} -d --runc-binary ${RUNK_BIN_PATH} --mount type=bind,src=${WORK_DIR},dst=/tmp,options=rbind:rw ${TEST_IMAGE} ${CONTAINER_ID} + read CID PID STATUS <<< $(sudo ctr t ls | grep ${CONTAINER_ID}) + [ ${PID} == $(cat ${PID_FILE}) ] || die "pid is not consistent" + [ ${STATUS} == "RUNNING" ] || die "container status is not RUNNING" + + echo "exec process in a container" + sudo ctr t exec --exec-id id1 ${CONTAINER_ID} sh -c "echo hello > /tmp/foo" + [ "hello" == "$(sudo ctr t exec --exec-id id1 ${CONTAINER_ID} cat /tmp/foo)" ] || die "exec process failed" + + echo "test ps command" + sudo ctr t exec --detach --exec-id id1 ${CONTAINER_ID} sh + # one line is the titles, and the other 2 lines are porcess info + [ "3" == "$(sudo ctr t ps ${CONTAINER_ID} | wc -l)" ] || die "ps command failed" + + echo "test pause and resume" + # The process outputs lines into /tmp/{CONTAINER_ID}, which can be read in host when it's frozon. + sudo ctr t exec --detach --exec-id id2 ${CONTAINER_ID} sh -c "while true; do echo hello >> /tmp/${CONTAINER_ID}; sleep 0.1; done" + # sleep for 1s to make sure the process outputs some lines + sleep 1 + sudo ctr t pause ${CONTAINER_ID} + [ "PAUSED" == "$(sudo ctr t ls | grep ${CONTAINER_ID} | grep -o PAUSED)" ] || die "status is not PAUSED" + echo "container is paused" + local TMP_FILE="${WORK_DIR}/${CONTAINER_ID}" + local lines1=$(cat ${TMP_FILE} | wc -l) + # sleep for a while and check the lines are not changed. + sleep 1 + local lines2=$(cat ${TMP_FILE} | wc -l) + [ ${lines1} == ${lines2} ] || die "paused container is still running" + sudo ctr t resume ${CONTAINER_ID} + [ "RUNNING" == "$(sudo ctr t ls | grep ${CONTAINER_ID} | grep -o RUNNING)" ] || die "status is not RUNNING" + echo "container is resumed" + # sleep for a while and check the lines are changed. + sleep 1 + local lines3=$(cat ${TMP_FILE} | wc -l) + [ ${lines2} -lt ${lines3} ] || die "resumed container is not running" + + echo "kill the container and poll until it is stopped" + sudo ctr t kill --signal SIGKILL --all ${CONTAINER_ID} + # poll for a while until the task receives signal and exit + local cmd='[ "STOPPED" == "$(sudo ctr t ls | grep ${CONTAINER_ID} | awk "{print \$3}")" ]' + waitForProcess 10 1 "${cmd}" || die "failed to kill task" + + echo "check the container is stopped" + # there is only title line of ps command + [ "1" == "$(sudo ctr t ps ${CONTAINER_ID} | wc -l)" ] || die "kill command failed" + + # High-level container runtimes such as containerd call the kill command with + # --all option in order to terminate all processes inside the container + # even if the container already is stopped. Hence, a low-level runtime + # should allow kill --all regardless of the container state like runc. + echo "test kill --all is allowed regardless of the container state" + sudo ctr t kill --signal SIGKILL ${CONTAINER_ID} && die "kill should fail" + sudo ctr t kill --signal SIGKILL --all ${CONTAINER_ID} || die "kill --all should not fail" + + echo "delete the container" + sudo ctr t rm ${CONTAINER_ID} + [ -z "$(sudo ctr t ls | grep ${CONTAINER_ID})" ] || die "failed to delete task" + sudo ctr c rm ${CONTAINER_ID} || die "failed to delete container" +} + +clean_up() { + rm -f ${PID_FILE} + rm -rf ${WORK_DIR} +} + +setup +test_runk +clean_up