Skip to content

Commit 64a9a18

Browse files
kvapsclaude
andcommitted
test(stand): burnin-blockstor — continuous PVC churn (default 24h)
Each iteration: kubectl apply RD + 2 Resources → wait UpToDate (60 s budget) → 1 MiB urandom write on Primary → failover → read on peer → md5 match → finalizer cleanup. Bails fast on convergence timeout or md5 mismatch — those are real regressions worth surfacing, not flakes to paper over. `make burnin-blockstor NAME=test DURATION=300` for a 5-min shake-down; default DURATION is 86400 (24h) — that's the PLAN '24h continuous PVC churn' item. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
1 parent a265004 commit 64a9a18

2 files changed

Lines changed: 130 additions & 1 deletion

File tree

stand/Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ KUBECONFIG := $(WORK_DIR)/kubeconfig
1313
export TALOSCONFIG
1414
export KUBECONFIG
1515

16-
.PHONY: stand-help up down reset piraeus oracle smoke smoke-blockstor use list stand-clean
16+
.PHONY: stand-help up down reset piraeus oracle smoke smoke-blockstor burnin-blockstor use list stand-clean
1717

1818
stand-help: ## list dev-stand targets
1919
@echo "stand targets (use NAME=<cluster>):"
@@ -40,6 +40,9 @@ smoke: ## run piraeus-stack smoke (PVC + linstor-csi) (NAME=<n>)
4040
smoke-blockstor: ## blockstor end-to-end smoke (RD → 2 replicas → bytes-perfect failover) (NAME=<n>)
4141
@./tests/smoke-blockstor.sh "$(WORK_DIR)"
4242

43+
burnin-blockstor: ## continuous PVC churn for DURATION seconds (default 86400 = 24h) (NAME=<n>, DURATION=<sec>)
44+
@./tests/burnin-blockstor.sh "$(WORK_DIR)" "$${DURATION:-86400}"
45+
4346
use: ## print TALOSCONFIG/KUBECONFIG exports for shell eval
4447
@echo "export TALOSCONFIG=$(abspath $(TALOSCONFIG))"
4548
@echo "export KUBECONFIG=$(abspath $(KUBECONFIG))"

tests/burnin-blockstor.sh

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#!/usr/bin/env bash
2+
#
3+
# usage: burnin-blockstor.sh WORK_DIR [DURATION_SEC]
4+
#
5+
# Continuous PVC churn against the deployed blockstor stack. Each
6+
# iteration:
7+
# - kubectl apply RD + 2 Resources (one auto-primary, one peer)
8+
# - wait for both UpToDate (≤60 s)
9+
# - 1 MiB urandom write on Primary, capture md5
10+
# - failover: Primary → Secondary, peer → Primary
11+
# - read on peer, compare md5 (must match — exits non-zero otherwise)
12+
# - delete Resource + RD via finalizer
13+
#
14+
# Default DURATION_SEC = 86400 (24h). The PLAN's "stand running for
15+
# 24h continuous PVC churn" item points at this script.
16+
#
17+
# Reports a summary every 60 iterations: pass/fail counts + recent
18+
# convergence timings.
19+
20+
set -euo pipefail
21+
22+
WORK_DIR=${1:?work_dir required}
23+
DURATION=${2:-86400}
24+
25+
export KUBECONFIG="$WORK_DIR/kubeconfig"
26+
27+
PRIMARY=test-worker-1
28+
PEER=test-worker-2
29+
NS=blockstor-system
30+
SIZE_KIB=65536 # 64 MiB
31+
DEADLINE=$(( $(date +%s) + DURATION ))
32+
33+
PASS=0
34+
FAIL=0
35+
ITER=0
36+
37+
# on_node runs a command in the satellite pod scheduled on a given node.
38+
on_node() {
39+
local node=$1
40+
shift
41+
local pod
42+
pod=$(kubectl -n "$NS" get pods -l app=blockstor-satellite \
43+
-o "jsonpath={.items[?(@.spec.nodeName==\"${node}\")].metadata.name}")
44+
kubectl -n "$NS" exec "$pod" -- "$@"
45+
}
46+
47+
cleanup_iter() {
48+
local rd=$1
49+
kubectl delete --wait=true --timeout=30s "resource.blockstor.io.blockstor.io/${rd}.${PRIMARY}" 2>/dev/null || true
50+
kubectl delete --wait=true --timeout=30s "resource.blockstor.io.blockstor.io/${rd}.${PEER}" 2>/dev/null || true
51+
kubectl delete --wait=true --timeout=30s "resourcedefinition.blockstor.io.blockstor.io/${rd}" 2>/dev/null || true
52+
}
53+
54+
while [[ $(date +%s) -lt $DEADLINE ]]; do
55+
ITER=$((ITER + 1))
56+
RD="burnin-${ITER}"
57+
58+
cat <<EOF | kubectl apply -f - >/dev/null
59+
apiVersion: blockstor.io.blockstor.io/v1alpha1
60+
kind: ResourceDefinition
61+
metadata: {name: ${RD}}
62+
spec:
63+
volumeDefinitions:
64+
- {volumeNumber: 0, sizeKib: ${SIZE_KIB}}
65+
---
66+
apiVersion: blockstor.io.blockstor.io/v1alpha1
67+
kind: Resource
68+
metadata: {name: ${RD}.${PRIMARY}}
69+
spec: {resourceDefinitionName: ${RD}, nodeName: ${PRIMARY}, props: {StorPoolName: stand}}
70+
---
71+
apiVersion: blockstor.io.blockstor.io/v1alpha1
72+
kind: Resource
73+
metadata: {name: ${RD}.${PEER}}
74+
spec: {resourceDefinitionName: ${RD}, nodeName: ${PEER}, props: {StorPoolName: stand}}
75+
EOF
76+
77+
# Wait for UpToDate convergence — bail out fast if it doesn't
78+
# land in 60 s, that's a regression we want to capture not paper over.
79+
BOTH=0
80+
for _ in $(seq 1 30); do
81+
p1=$(on_node "$PRIMARY" drbdsetup status "$RD" 2>/dev/null | grep "disk:" | head -1 || true)
82+
p2=$(on_node "$PEER" drbdsetup status "$RD" 2>/dev/null | grep "disk:" | head -1 || true)
83+
if [[ "$p1" == *"disk:UpToDate"* && "$p2" == *"disk:UpToDate"* ]]; then
84+
BOTH=1
85+
break
86+
fi
87+
sleep 2
88+
done
89+
90+
if [[ $BOTH -ne 1 ]]; then
91+
FAIL=$((FAIL + 1))
92+
echo "[$(date -u +%FT%TZ)] iter=$ITER FAIL: convergence timeout"
93+
cleanup_iter "$RD"
94+
continue
95+
fi
96+
97+
DEV=$(on_node "$PRIMARY" bash -c "grep -oE '/dev/drbd[0-9]+' /etc/drbd.d/${RD}.res | head -1")
98+
PRIMARY_MD5=$(on_node "$PRIMARY" bash -c "
99+
drbdadm primary ${RD}
100+
dd if=/dev/urandom of=${DEV} bs=1M count=1 status=none oflag=direct
101+
dd if=${DEV} bs=1M count=1 status=none iflag=direct | md5sum | awk '{print \$1}'
102+
drbdadm secondary ${RD}
103+
" | tail -1)
104+
105+
PEER_MD5=$(on_node "$PEER" bash -c "
106+
drbdadm primary ${RD}
107+
dd if=${DEV} bs=1M count=1 status=none iflag=direct | md5sum | awk '{print \$1}'
108+
drbdadm secondary ${RD}
109+
" | tail -1)
110+
111+
if [[ "$PRIMARY_MD5" == "$PEER_MD5" ]]; then
112+
PASS=$((PASS + 1))
113+
else
114+
FAIL=$((FAIL + 1))
115+
echo "[$(date -u +%FT%TZ)] iter=$ITER FAIL: md5 mismatch primary=$PRIMARY_MD5 peer=$PEER_MD5"
116+
fi
117+
118+
cleanup_iter "$RD"
119+
120+
if (( ITER % 60 == 0 )); then
121+
echo "[$(date -u +%FT%TZ)] iter=$ITER pass=$PASS fail=$FAIL elapsed=$(( $(date +%s) - DEADLINE + DURATION ))s"
122+
fi
123+
done
124+
125+
echo "[$(date -u +%FT%TZ)] DONE iter=$ITER pass=$PASS fail=$FAIL"
126+
[[ $FAIL -eq 0 ]] || exit 1

0 commit comments

Comments
 (0)