conformance: fix invalid test-level spec.finally for chainsaw v0.2.12
chainsaw v0.2.12 has no test-level `spec.finally` (finally exists only on a
step), and a step-level `finally` accepts only catch-style ops (script/command/
delete/wait), NOT `apply`/`assert`. Both tests failed to parse ("unknown field").
- egress-class: drop the redundant test-level `spec.finally` delete-pods block —
chainsaw auto-deletes applied fixtures on cleanup (skipDelete: false). The
valid step-level `finally` that restores the egress-class label is kept.
- vpn-killswitch: move the SAFETY-CRITICAL self-healing tunnel restart out of the
invalid `spec.finally` and into the STEP-level `finally` of the fault step
`when-force-tunnel-down-then-no-leak`, implemented as a `script` (finally can't
use apply/assert) that `kubectl apply`s the privileged node-pinned restart Job
(name `tunnel-restart`, distinct from `tunnel-stop`) and `kubectl wait`s for it
to complete — the equivalent of `assert succeeded:1`, blocking teardown until
the host confirms the tunnel is up. This finally runs even if the no-leak /
internet-unaffected asserts in the same step's `try` fail, so no path leaves the
gateway tunnel down. The recovery step is now poll-only (restart already
happened in the prior step's finally).
Validation with the pinned binary (~/.local/bin/chainsaw v0.2.12):
`chainsaw lint test --file ...` => "The document is valid" for both; `chainsaw
test ... --no-cluster` loads both past the parse stage (no "unknown field"), then
fails only at runtime for lack of a cluster (expected). yamllint + run.sh
--strict-coverage clean (RC=0). No live apply / fault injection, no spec edits.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
0e69c63b55
commit
4c21f9f6e3
2 files changed
+41
-99
No files matched your search
@@ -158,13 +158,6 @@ spec:
|
|||||||
homelab.keithjackson.dev/egress-class=vpn --overwrite
|
homelab.keithjackson.dev/egress-class=vpn --overwrite
|
||||||
echo "restored egress-class=vpn"
|
echo "restored egress-class=vpn"
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Fixtures are deleted by Chainsaw's per-test namespace teardown; this explicit
|
# Fixtures are torn down automatically by Chainsaw's per-test namespace deletion
|
||||||
# finally is belt-and-suspenders so a leaked pod is impossible even if the ns
|
# (config/chainsaw-config.yaml sets skipDelete: false), so no explicit fixture
|
||||||
# deletion is ever disabled.
|
# cleanup step is needed — and chainsaw v0.2.12 has no test-level spec.finally.
|
||||||
finally:
|
|
||||||
- delete:
|
|
||||||
ref:
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Pod
|
|
||||||
labels:
|
|
||||||
app: egress-test
|
|
||||||
@@ -196,19 +196,32 @@ spec:
|
|||||||
echo "INTERNET_UNAFFECTED_OK"
|
echo "INTERNET_UNAFFECTED_OK"
|
||||||
check:
|
check:
|
||||||
(contains($stdout, 'INTERNET_UNAFFECTED_OK')): true
|
(contains($stdout, 'INTERNET_UNAFFECTED_OK')): true
|
||||||
# ---------------------------------------------------------------------------
|
# -- SELF-HEALING (STEP-LEVEL finally — chainsaw v0.2.12 has NO test-level
|
||||||
- name: when-tunnel-recovers-connectivity-returns
|
# spec.finally; finally lives on the step, and it only accepts catch-style ops
|
||||||
try:
|
# like `script`, NOT `apply`/`assert`). This runs ALWAYS, even if a `try`
|
||||||
# -- Restart the host tunnel service and prove vpn-class egress comes back. --
|
# assertion above FAILED, so a failed no-leak / internet-unaffected assertion
|
||||||
- apply:
|
# can never leave the gateway tunnel down. This is the ONLY step that stops the
|
||||||
resource:
|
# tunnel, so restarting it here closes every path to a leaked-down gateway.
|
||||||
|
# We create the privileged restart Job with kubectl and `kubectl wait` for it —
|
||||||
|
# the equivalent of an `assert succeeded:1`: teardown blocks until the host
|
||||||
|
# confirms the unit is back up. Idempotent: `systemctl start` on an already-
|
||||||
|
# running unit is a no-op success.
|
||||||
|
finally:
|
||||||
|
- script:
|
||||||
|
content: |
|
||||||
|
set -eu
|
||||||
|
ns="$NAMESPACE"
|
||||||
|
# Distinct Job name (tunnel-restart) so it never collides with the
|
||||||
|
# tunnel-stop Job. Left-aligned manifest so the block scalar yields
|
||||||
|
# valid YAML at column 0 at runtime.
|
||||||
|
cat <<'JOB' | kubectl -n "$ns" apply -f -
|
||||||
apiVersion: batch/v1
|
apiVersion: batch/v1
|
||||||
kind: Job
|
kind: Job
|
||||||
metadata:
|
metadata:
|
||||||
name: tunnel-start
|
name: tunnel-restart
|
||||||
labels: { app: vpn-killswitch-fault }
|
labels: { app: vpn-killswitch-fault }
|
||||||
spec:
|
spec:
|
||||||
backoffLimit: 2
|
backoffLimit: 3
|
||||||
activeDeadlineSeconds: 90
|
activeDeadlineSeconds: 90
|
||||||
ttlSecondsAfterFinished: 600
|
ttlSecondsAfterFinished: 600
|
||||||
template:
|
template:
|
||||||
@@ -226,28 +239,22 @@ spec:
|
|||||||
image: busybox:1.37.0
|
image: busybox:1.37.0
|
||||||
securityContext:
|
securityContext:
|
||||||
privileged: true
|
privileged: true
|
||||||
command:
|
command: ["nsenter","-t","1","-m","-u","-i","-n","-p","--","systemctl","start","vpn-egress-tunnel"]
|
||||||
- nsenter
|
JOB
|
||||||
- "-t"
|
# Block teardown until the restart actually completed on the host — a
|
||||||
- "1"
|
# leaked-down tunnel is unacceptable. `wait` exits non-zero on failure
|
||||||
- "-m"
|
# or timeout, which (set -e) fails the step and surfaces the problem.
|
||||||
- "-u"
|
kubectl -n "$ns" wait --for=condition=complete --timeout=110s job/tunnel-restart
|
||||||
- "-i"
|
echo "TUNNEL_SELF_HEAL_OK"
|
||||||
- "-n"
|
check:
|
||||||
- "-p"
|
(contains($stdout, 'TUNNEL_SELF_HEAL_OK')): true
|
||||||
- "--"
|
# ---------------------------------------------------------------------------
|
||||||
- systemctl
|
- name: when-tunnel-recovers-connectivity-returns
|
||||||
- start
|
# The tunnel was already restarted by the previous step's self-healing
|
||||||
- vpn-egress-tunnel
|
# `finally`; here we prove the EFFECT — vpn-class egress returns to a NON-WAN
|
||||||
- assert:
|
# (PIA) IP within a bounded window (tunnel reconnect + datapath convergence).
|
||||||
resource:
|
try:
|
||||||
apiVersion: batch/v1
|
|
||||||
kind: Job
|
|
||||||
metadata: { name: tunnel-start }
|
|
||||||
status: { succeeded: 1 }
|
|
||||||
- script:
|
- script:
|
||||||
# Poll (bounded) until the tunnel reconnects and vpn-class egress returns
|
|
||||||
# to a NON-WAN (PIA) IP — connectivity restored, still tunneled.
|
|
||||||
content: |
|
content: |
|
||||||
set -eu
|
set -eu
|
||||||
ns="$NAMESPACE"
|
ns="$NAMESPACE"
|
||||||
@@ -267,63 +274,5 @@ spec:
|
|||||||
echo "TUNNEL_RECOVERED_OK"
|
echo "TUNNEL_RECOVERED_OK"
|
||||||
check:
|
check:
|
||||||
(contains($stdout, 'TUNNEL_RECOVERED_OK')): true
|
(contains($stdout, 'TUNNEL_RECOVERED_OK')): true
|
||||||
# ---------------------------------------------------------------------------
|
# Fault Jobs + fixtures are torn down automatically by Chainsaw's per-test
|
||||||
# SELF-HEALING: no matter how any step above ended, ALWAYS start the tunnel so a
|
# namespace deletion (config/chainsaw-config.yaml: skipDelete: false).
|
||||||
# mid-test failure never leaves the gateway down. Idempotent: `systemctl start` on
|
|
||||||
# an already-running unit is a no-op success. Distinct Job name so it never
|
|
||||||
# collides with the recovery-step Job.
|
|
||||||
finally:
|
|
||||||
- apply:
|
|
||||||
resource:
|
|
||||||
apiVersion: batch/v1
|
|
||||||
kind: Job
|
|
||||||
metadata:
|
|
||||||
name: tunnel-start-finally
|
|
||||||
labels: { app: vpn-killswitch-fault }
|
|
||||||
spec:
|
|
||||||
backoffLimit: 3
|
|
||||||
activeDeadlineSeconds: 90
|
|
||||||
ttlSecondsAfterFinished: 600
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels: { app: vpn-killswitch-fault }
|
|
||||||
spec:
|
|
||||||
restartPolicy: Never
|
|
||||||
hostPID: true
|
|
||||||
nodeSelector:
|
|
||||||
homelab.keithjackson.dev/egress-gateway: "true"
|
|
||||||
tolerations:
|
|
||||||
- operator: Exists
|
|
||||||
containers:
|
|
||||||
- name: nsenter
|
|
||||||
image: busybox:1.37.0
|
|
||||||
securityContext:
|
|
||||||
privileged: true
|
|
||||||
command:
|
|
||||||
- nsenter
|
|
||||||
- "-t"
|
|
||||||
- "1"
|
|
||||||
- "-m"
|
|
||||||
- "-u"
|
|
||||||
- "-i"
|
|
||||||
- "-n"
|
|
||||||
- "-p"
|
|
||||||
- "--"
|
|
||||||
- systemctl
|
|
||||||
- start
|
|
||||||
- vpn-egress-tunnel
|
|
||||||
# Block until the self-healing start actually completed on the host before the
|
|
||||||
# namespace (and this Job) is torn down — a leaked-down tunnel is unacceptable.
|
|
||||||
- assert:
|
|
||||||
resource:
|
|
||||||
apiVersion: batch/v1
|
|
||||||
kind: Job
|
|
||||||
metadata: { name: tunnel-start-finally }
|
|
||||||
status: { succeeded: 1 }
|
|
||||||
# Clean up the fault Jobs (belt-and-suspenders; ns teardown also removes them).
|
|
||||||
- delete:
|
|
||||||
ref:
|
|
||||||
apiVersion: batch/v1
|
|
||||||
kind: Job
|
|
||||||
labels:
|
|
||||||
app: vpn-killswitch-fault
|
|
||||||
Reference in new issue
Block a user