From a86196e9556dfe98367e8b0751d4851f38e1e3c3 Mon Sep 17 00:00:00 2001 From: Josh Wolf Date: Mon, 3 Feb 2025 11:24:54 -0500 Subject: [PATCH] plumb through exec instead of assuming /bin/sh (#290) instead of assuming `CMD` is a shell script, just use `exec`. this means we can support any valid `CMD`, with the downside that shell scripts will now need to set their own setopts. we trade some transparency for more compatibility and control. this also cleans up the scripts logging a bit, and adds a `socat` registry proxy to support local registries for the dind driver. the `socat` works almost identically to how containerd mirroring is done with the k3sindocker driver. --- cmd/entrypoint/kodata/entrypoint-wrapper.sh | 92 +++++++++++++-------- internal/provider/tests_resource.go | 2 + 2 files changed, 59 insertions(+), 35 deletions(-) diff --git a/cmd/entrypoint/kodata/entrypoint-wrapper.sh b/cmd/entrypoint/kodata/entrypoint-wrapper.sh index 0f76713..57d5898 100644 --- a/cmd/entrypoint/kodata/entrypoint-wrapper.sh +++ b/cmd/entrypoint/kodata/entrypoint-wrapper.sh @@ -1,11 +1,23 @@ #!/bin/sh set -eu +info() { + printf '%s [INFO] %s\n' "$(date "+%Y-%m-%dT%H:%M:%S")" "$1" >&2 +} + +warn() { + printf '%s [WARN] %s\n' "$(date "+%Y-%m-%dT%H:%M:%S")" "$1" >&2 +} + +error() { + printf '%s [ERROR] %s\n' "$(date "+%Y-%m-%dT%H:%M:%S")" "$1" >&2 +} + # Print usage and exit with error usage() { - echo "Usage: $0 " - echo "Environment variables:" - echo " IMAGETEST_DRIVER: Type of test environment (docker_in_docker, k3s_in_docker)" + error "Usage: $0 " + error "Environment variables:" + error " IMAGETEST_DRIVER: Type of test environment (docker_in_docker, k3s_in_docker)" exit 1 } @@ -13,22 +25,31 @@ usage() { # This function is used by all drivers to ensure consistent validation. # Arguments: # $1: Path to the test script -validate_test_script() { - script_path="$1" +validate_cmd() { + cmdarg="$1" - if [ ! -f "$script_path" ]; then - echo "Error: Test script '$script_path' does not exist" - exit 1 + # Only try to do validations if cmdarg is a file (presumably a script of sorts) + if [ -f "$cmdarg" ]; then + if [ ! -x "$cmdarg" ]; then + chmod +x "$cmdarg" || warn "Failed to make script executable" + fi fi +} + +init_registry_proxy() { + case "${IMAGETEST_REGISTRY}" in + "localhost:"*) + info "Attempting to start registry proxy" - if [ ! -x "$script_path" ]; then - echo "Warning: Test script '$script_path' is not executable, attempting to set execute permission" - if ! chmod +x "$script_path"; then - echo "Error: Failed to make test script executable" - exit 1 + port=$(echo "$IMAGETEST_REGISTRY" | sed -n 's/^localhost:\([0-9]\+\).*/\1/p') + if [ -n "${port}" ]; then + info "Detected localhost and port ${port}, starting registry proxy" + + # Start a non-forked socat process to proxy localhost to dockers magic dns + setsid socat -d -lf /tmp/local-registry-proxy.log TCP-LISTEN:"${port}",fork,reuseaddr TCP:host.docker.internal:"${port}" /dev/null 2>&1 & fi - echo "Successfully made test script executable" - fi + ;; + esac } # Initialize and manage a Docker-in-Docker environment. @@ -36,7 +57,7 @@ validate_test_script() { # Arguments: # $1: Path to the test script (already validated) init_docker_in_docker() { - test_script="$1" + cmd="$1" timeout=30 log_dir="/var/log/docker" @@ -47,46 +68,47 @@ init_docker_in_docker() { /usr/bin/dockerd-entrypoint.sh dockerd >"$log_dir/dockerd.log" 2>&1 & # Wait for Docker to be ready - echo "Waiting for Docker daemon to be ready..." + info "Waiting for Docker daemon to be ready..." while [ "$timeout" -gt 0 ]; do if docker version >/dev/null 2>&1; then - echo "Docker daemon is ready" + info "Docker daemon is ready" break fi timeout=$((timeout - 1)) - echo "Waiting... ($timeout seconds remaining)" + info "Waiting... ($timeout seconds remaining)" sleep 1 done if [ "$timeout" -le 0 ]; then - echo "Error: Docker daemon failed to start" + error "Docker daemon failed to start" exit 1 fi - # Execute test script with strict shell options - exec /bin/sh -euxc ". $test_script" + # Maybe start a registry proxy + init_registry_proxy + + exec "$cmd" } # Initialize and manage a K3s-in-Docker environment. # Arguments: # $1: Path to the test script (already validated) init_k3s_in_docker() { - test_script="$1" + cmd="$1" # Ensure required environment variables are set if [ -z "${POD_NAME-}" ] || [ -z "${POD_NAMESPACE-}" ]; then - echo "Error: POD_NAME and POD_NAMESPACE environment variables must be set" + error "POD_NAME and POD_NAMESPACE environment variables must be set" exit 1 fi - echo "Waiting for pod ${POD_NAME} to be ready..." - if ! kubectl wait --for=condition=Ready=true pod/${POD_NAME} -n "${POD_NAMESPACE}" --timeout=60s; then - echo "Error: Pod ${POD_NAME} failed to become ready" + info "Waiting for pod ${POD_NAME} to be ready..." + if ! kubectl wait --for=condition=Ready=true pod/"${POD_NAME}" -n "${POD_NAMESPACE}" --timeout=60s; then + error "Pod ${POD_NAME} failed to become ready" exit 1 fi - # Execute test script with strict shell options - exec /bin/sh -euxc ". $test_script" + exec "$cmd" } # Validate command-line arguments @@ -94,27 +116,27 @@ if [ $# -ne 1 ]; then usage fi -test_script="$1" +cmd="$1" # Make sure IMAGETEST_DRIVER is set if [ -z "${IMAGETEST_DRIVER-}" ]; then - echo "Error: IMAGETEST_DRIVER environment variable not set" + error "IMAGETEST_DRIVER environment variable not set" usage fi # Validate the test script first, regardless of driver -validate_test_script "$test_script" +validate_cmd "$cmd" # Initialize the appropriate driver case "$IMAGETEST_DRIVER" in docker_in_docker) - init_docker_in_docker "$test_script" + init_docker_in_docker "$cmd" ;; k3s_in_docker) - init_k3s_in_docker "$test_script" + init_k3s_in_docker "$cmd" ;; *) - echo "Error: Unknown driver '$IMAGETEST_DRIVER'" + error "Unknown driver '$IMAGETEST_DRIVER'" usage ;; esac diff --git a/internal/provider/tests_resource.go b/internal/provider/tests_resource.go index 6bc50af..74a76dd 100644 --- a/internal/provider/tests_resource.go +++ b/internal/provider/tests_resource.go @@ -337,6 +337,8 @@ func (t *TestsResource) do(ctx context.Context, data *TestsResourceModel) (ds di } envs["IMAGES"] = string(imgsResolvedData) envs["IMAGETEST_DRIVER"] = string(data.Driver) + envs["IMAGETEST_REGISTRY"] = t.repo.RegistryStr() + envs["IMAGETEST_REPO"] = t.repo.String() if os.Getenv("IMAGETEST_SKIP_TEARDOWN_ON_FAILURE") != "" || os.Getenv("IMAGETEST_SKIP_TEARDOWN") != "" { envs["IMAGETEST_PAUSE_ON_ERROR"] = "true"