# ============================================================================= # L3 FAULT-INJECTION — Data survival on rebuild (R-STATE-01) [RUNNABLE / self-skips] # *SAFETY-CRITICAL* # Catalog: docs/14 "Data survival (R-STATE-01, L3)" # Spec: docs/04-storage-and-state.md # # GIVEN a stateful workload with written data on a longhorn-backed PVC, # WHEN the workload is DESTROYED entirely and a fresh one re-bound to the PVC, # THEN the data is intact. # # R-TEST-05: proves no-data-loss by actually destroying the workload (not a # happy-path read). The PVC is kept; the pod is deleted and rebuilt. # # RUNNABLE / SELF-SKIPPING: Longhorn (T-2.1) is not on the base cluster yet. # This test SKIPS CLEANLY (green) when no `longhorn` StorageClass exists, and # runs the full destroy/rebuild survival check the moment one does — no edit # needed. Hermetic: PVC + pods live in the chainsaw per-test namespace and are # torn down with it. # ============================================================================= apiVersion: chainsaw.kyverno.io/v1alpha1 kind: Test metadata: name: data-survival labels: conformance.home.k3s/R-STATE-01: "true" annotations: conformance.home.k3s/requirements: "R-STATE-01" conformance.home.k3s/layer: "L3" conformance.home.k3s/safety-critical: "true" # executable => runs against a cluster; self-skips (green) until longhorn exists. conformance.home.k3s/executable: "true" conformance.home.k3s/intent: >- Destroy the workload entirely and re-bind a fresh one to the same longhorn PVC; written data survives. Skips cleanly until a longhorn StorageClass exists. spec: steps: - name: data-survives-destroy-and-rebuild try: - script: content: | set -euo pipefail NS="$NAMESPACE" # -- Gate: skip cleanly (green) if the longhorn tier is not present yet. -- if ! kubectl get storageclass longhorn >/dev/null 2>&1; then echo "SKIP: 'longhorn' StorageClass absent — data-survival not applicable on this cluster yet" echo DATA_SURVIVAL_SKIPPED_OK exit 0 fi CANARY="conformance-canary-$(date +%s%N)" # -- GIVEN: a PVC on longhorn + a writer pod that writes the canary. -- kubectl -n "$NS" apply -f - < /data/canary && sync' echo "wrote canary: $(kubectl -n "$NS" exec writer -- cat /data/canary)" # -- WHEN: FAULT INJECTION — destroy the workload ENTIRELY (keep the PVC). -- kubectl -n "$NS" delete pod writer --wait=true --timeout=180s kubectl -n "$NS" get pvc survivor # PVC must still exist # -- THEN: a fresh workload re-bound to the same PVC still sees the data. -- apply_pod reader kubectl -n "$NS" wait --for=condition=Ready pod/reader --timeout=240s GOT="$(kubectl -n "$NS" exec reader -- cat /data/canary)" echo "recovered=$GOT expected=$CANARY" [ "$GOT" = "$CANARY" ] && echo DATA_SURVIVED_OK check: # green on either a clean skip (no longhorn) or a proven survival. (contains($stdout, 'DATA_SURVIVED_OK') || contains($stdout, 'DATA_SURVIVAL_SKIPPED_OK')): true finally: - script: content: | kubectl -n "$NAMESPACE" delete pod writer reader --ignore-not-found --wait=false || true kubectl -n "$NAMESPACE" delete pvc survivor --ignore-not-found --wait=false || true echo "cleanup best-effort; chainsaw namespace teardown finalizes"