#!/usr/bin/env bash set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" TESTBED="$ROOT/tests/kind" RUNTIME="$TESTBED/.runtime" BIN="$RUNTIME/bin" KUBECONFIG_PATH="$RUNTIME/kubeconfig" CONTEXT=kind-remora-testbed CLUSTER=remora-testbed NERDCTL_NAMESPACE=remora-wp02 set -a source "$TESTBED/versions.env" set +a user_kubeconfig_digest() { local config_value="${KUBECONFIG:-${HOME:?}/.kube/config}" local path local paths IFS=: read -r -a paths <<< "$config_value" { for path in "${paths[@]}"; do if [[ -f "$path" ]]; then sha256sum "$path" else printf 'missing %s\n' "$path" fi done } | sha256sum | cut -d' ' -f1 } download_tool() { local destination="$1" local checksum="$2" local url="$3" if [[ -x "$destination" ]] && [[ "$(sha256sum "$destination" | cut -d' ' -f1)" = "$checksum" ]]; then return fi curl --fail --location --silent --show-error "$url" --output "$destination.tmp" test "$(sha256sum "$destination.tmp" | cut -d' ' -f1)" = "$checksum" chmod 0755 "$destination.tmp" mv "$destination.tmp" "$destination" } prepare_tools() { mkdir -p "$BIN" download_tool \ "$BIN/kind" \ "$KIND_SHA256" \ "https://github.com/kubernetes-sigs/kind/releases/download/$KIND_VERSION/kind-linux-amd64" download_tool \ "$BIN/kubectl" \ "$KUBECTL_SHA256" \ "https://dl.k8s.io/release/$KUBECTL_VERSION/bin/linux/amd64/kubectl" test "$("$BIN/kind" version | awk '{print $2}')" = "$KIND_VERSION" test "$("$BIN/kubectl" --kubeconfig "$KUBECONFIG_PATH" --context "$CONTEXT" version --client=true -o json | jq -r .clientVersion.gitVersion)" = "$KUBECTL_VERSION" test "$(nerdctl --version | awk '{print $3}')" = 2.3.4 } prepare_provider() { configure_provider delete_cluster remove_runtime_namespace "$REMORA_REAL_NERDCTL" namespace create "$NERDCTL_NAMESPACE" >/dev/null } configure_provider() { REMORA_REAL_NERDCTL="$(command -v nerdctl)" export REMORA_REAL_NERDCTL export CONTAINERD_NAMESPACE="$NERDCTL_NAMESPACE" export KIND_EXPERIMENTAL_PROVIDER=nerdctl export PATH="$TESTBED/provider:$PATH" } remove_runtime_namespace() { local status=0 if ! runtime_namespace_exists; then return fi "$REMORA_REAL_NERDCTL" --namespace "$NERDCTL_NAMESPACE" image prune --all --force >/dev/null || status=1 "$REMORA_REAL_NERDCTL" namespace remove "$NERDCTL_NAMESPACE" >/dev/null || status=1 if runtime_namespace_exists; then printf 'containerd namespace %s still exists after teardown\n' "$NERDCTL_NAMESPACE" >&2 status=1 fi return "$status" } runtime_namespace_exists() { "$REMORA_REAL_NERDCTL" namespace list --quiet | grep -Fx "$NERDCTL_NAMESPACE" >/dev/null } cluster_exists() { if ! runtime_namespace_exists; then return 1 fi "$BIN/kind" get clusters | grep -Fx "$CLUSTER" >/dev/null } delete_cluster() { if cluster_exists; then "$BIN/kind" delete cluster --name "$CLUSTER" fi if cluster_exists; then printf 'kind cluster %s still exists after teardown\n' "$CLUSTER" >&2 return 1 fi } load_external_image() { local name="$1" local source="$2" local digest="${source##*@}" local image="remora-testbed/$name:sha256-${digest#sha256:}" local archive="$RUNTIME/image-archives/$digest.tar" "$REMORA_REAL_NERDCTL" image pull --platform linux/amd64 --unpack=false --quiet "$source" >&2 || return 1 "$REMORA_REAL_NERDCTL" image tag "$source" "$image" || return 1 "$REMORA_REAL_NERDCTL" image save --platform linux/amd64 --output "$archive" "$image" || return 1 printf 'Loading %s from %s\n' "$image" "$source" >&2 "$BIN/kind" load image-archive "$archive" --name "$CLUSTER" >&2 || return 1 printf '%s\n' "$image" } render_manifests() { local postgres_image="$1" local redis_image="$2" local dragonfly_image="$3" local vault_image="$4" local keycloak_image="$5" local zitadel_image="$6" local garage_image="$7" local versitygw_image="$8" local coredns_image="$9" local curl_image="${10}" local aws_cli_image="${11}" sed \ -e "s|@@POSTGRES_IMAGE@@|$postgres_image|g" \ -e "s|@@REDIS_IMAGE@@|$redis_image|g" \ -e "s|@@DRAGONFLY_IMAGE@@|$dragonfly_image|g" \ -e "s|@@VAULT_IMAGE@@|$vault_image|g" \ -e "s|@@KEYCLOAK_IMAGE@@|$keycloak_image|g" \ -e "s|@@ZITADEL_IMAGE@@|$zitadel_image|g" \ -e "s|@@GARAGE_IMAGE@@|$garage_image|g" \ -e "s|@@VERSITYGW_IMAGE@@|$versitygw_image|g" \ -e "s|@@COREDNS_IMAGE@@|$coredns_image|g" \ -e "s|@@CURL_IMAGE@@|$curl_image|g" \ -e "s|@@AWS_CLI_IMAGE@@|$aws_cli_image|g" \ "$TESTBED/dependencies.yaml.in" > "$RUNTIME/dependencies.yaml" sed \ -e "s|@@POSTGRES_IMAGE@@|$postgres_image|g" \ -e "s|@@REDIS_IMAGE@@|$redis_image|g" \ -e "s|@@VAULT_IMAGE@@|$vault_image|g" \ -e "s|@@CURL_IMAGE@@|$curl_image|g" \ -e "s|@@AWS_CLI_IMAGE@@|$aws_cli_image|g" \ "$TESTBED/probe.yaml.in" > "$RUNTIME/probe.yaml" } kube() { "$BIN/kubectl" \ --kubeconfig "$KUBECONFIG_PATH" \ --context "$CONTEXT" \ "$@" } wait_for_job() { local job="$1" local deadline=$((SECONDS + 300)) local complete local failed while ((SECONDS < deadline)); do complete="$(kube --namespace remora-testbed get "job/$job" --output jsonpath='{.status.conditions[?(@.type=="Complete")].status}')" if [[ "$complete" = True ]]; then kube --namespace remora-testbed logs "job/$job" --all-containers return fi failed="$(kube --namespace remora-testbed get "job/$job" --output jsonpath='{.status.conditions[?(@.type=="Failed")].status}')" if [[ "$failed" = True ]]; then kube --namespace remora-testbed logs "job/$job" --all-containers >&2 || true return 1 fi sleep 1 done printf 'job/%s did not complete within 300 seconds\n' "$job" >&2 return 1 }