hack/proxmox-step1b-pod-match_test.bats
Rama main · réplica de lectura del repositorio original.
#!/usr/bin/env bats
# -----------------------------------------------------------------------------
# Step 1b of the proxmox pre-delete hook deletes the Pods that hold each tenant
# claim, so the claims' pvc-protection finalizer can clear and the CSI driver
# frees the disks before Step 2 removes it. A render test cannot see how the
# loop behaves, because it never runs kubectl. These tests do: they render the
# hook, cut the Pod loop out of it, and run it against a stub kubectl whose
# `get pods` answers with the listing the loop asks for.
#
# The case that matters is a namespace where one Pod mounts two claims. A
# JSONPath filter on the claim name fails there for every claim in the
# namespace ("can only compare one element at a time"), kubectl prints nothing,
# and no Pod is deleted; the listing-plus-shell-match form does not.
# -----------------------------------------------------------------------------
load test_helper
# The legacy hack/cozytest.sh translator runs @test bodies as POSIX sh functions
# and knows no setup/teardown; the tests stay compatible with it, so each test
# calls prepare_loop and removes $work itself.
prepare_loop() {
work=$(mktemp -d)
cat > "$work/vals.yaml" <<'VALS'
substrate: proxmox
_namespace:
etcd: etcd-test
proxmox:
dnsServers: ["8.8.8.8"]
ipv4Config:
addresses: ["10.0.0.160-10.0.0.170"]
gateway: "10.0.0.1"
prefix: 24
ccm:
credentialsSecretName: proxmox-ccm-creds
csi:
enabled: true
credentialsSecretName: proxmox-csi-creds
VALS
helm template test-k8s packages/apps/kubernetes -n tenant-test \
-f packages/apps/kubernetes/tests/values-ci.yaml -f "$work/vals.yaml" \
--show-only templates/delete.yaml > "$work/hook.yaml"
# The Job's script, as the container receives it.
yq -r 'select(.kind == "Job") | .spec.template.spec.containers[0].command[2]' \
"$work/hook.yaml" > "$work/script.sh"
# The Pod loop alone: from the second `echo "$pvcs" | while` to the `done`
# that closes it at the same indentation.
awk '
/echo "\$pvcs" \| while read -r pns pname pv; do/ { n++; if (n == 2) { grab = 1; indent = match($0, /[^ ]/) } }
grab { print }
grab && /^[ ]*done[ ]*$/ && match($0, /[^ ]/) == indent { exit }
' "$work/script.sh" > "$work/loop.sh"
[ -s "$work/loop.sh" ] || { echo "could not cut the Pod loop out of the hook" >&2; exit 1; }
mkdir -p "$work/bin"
# Stub kubectl, faithful to client-go's JSONPath for the two forms the loop
# can use. `get pods` with the per-Pod listing prints one line per Pod: its
# name, then the claims it mounts. `get pods` with a claim-name filter does
# what kubectl does: as soon as any Pod mounts more than one claim, the
# filter's left side has several values and the whole expression fails with
# "can only compare one element at a time", printing nothing. `delete pod`
# records the Pod. Nothing else may be called from this loop.
cat > "$work/bin/kubectl" <<'STUB'
#!/bin/sh
case " $* " in
*" get pods "*)
case "$*" in
*'[?(@.spec.volumes'*)
if awk 'NF > 2 { found = 1 } END { exit !found }' "$PODS"; then
echo "error: error executing jsonpath: can only compare one element at a time" >&2
exit 1
fi
claim=$(printf '%s' "$*" | sed -n "s/.*claimName=='\([^']*\)'.*/\1/p")
awk -v c="$claim" '$2 == c { print $1 }' "$PODS" ;;
*) cat "$PODS" ;;
esac ;;
*" delete pod "*) prev=; for a in "$@"; do [ "$prev" = pod ] && echo "$a" >> "$DELETED"; prev=$a; done ;;
*) echo "unexpected kubectl call: $*" >&2; exit 3 ;;
esac
STUB
chmod +x "$work/bin/kubectl"
export PATH="$work/bin:$PATH" PODS="$work/pods" DELETED="$work/deleted"
: > "$DELETED"
printf '%s\n' "db-0 data-b wal-b" "web-0 data-a" "cfg-0 " > "$PODS"
}
run_loop_for() {
sh -c 'kubeconfig=/dev/null; pvcs=$1; . "$2"' _ "$1" "$work/loop.sh"
}
@test "deletes the Pod that mounts two claims, for either claim" {
prepare_loop
run_loop_for "app wal-b pv-1"
got=$(cat "$DELETED"); rm -rf "$work"
[ "$got" = "db-0" ]
}
@test "deletes a one-claim Pod in a namespace where another Pod mounts two" {
prepare_loop
run_loop_for "app data-a pv-2"
got=$(cat "$DELETED"); rm -rf "$work"
[ "$got" = "web-0" ]
}
@test "matches whole claim names only" {
prepare_loop
run_loop_for "app data pv-3"
got=$(cat "$DELETED"); rm -rf "$work"
[ -z "$got" ]
}
@test "leaves a Pod that mounts no claim alone" {
prepare_loop
run_loop_for "app data-b pv-4"
got=$(cat "$DELETED"); rm -rf "$work"
[ "$got" = "db-0" ]
}