@@ -17,6 +17,9 @@ THRESHOLD_KB=5120 # 5 MB growth limit
1717NODE_COUNT=100
1818TEST_NAMESPACE=" ${TEST_NAMESPACE:- soak-test} "
1919RESULTS_FILE=" ${RESULTS_FILE:-/ tmp/ soak-memory.log} "
20+ CLEANUP_DONE=false
21+ CLEANUP_TIMEOUT_SECONDS=" ${CLEANUP_TIMEOUT_SECONDS:- 120} "
22+ RETRY_DELAY_SECONDS=" ${RETRY_DELAY_SECONDS:- 15} "
2023
2124# ── Helpers ──────────────────────────────────────────────────────────────────
2225
@@ -26,6 +29,36 @@ get_operator_pid() {
2629 -o jsonpath=' {.items[0].metadata.name}' 2> /dev/null
2730}
2831
32+ validate_positive_integer () {
33+ local name=" $1 "
34+ local value=" $2 "
35+ if ! [[ " $value " =~ ^[0-9]+$ ]]; then
36+ echo " ERROR: ${name} must be an integer, got '${value} '"
37+ exit 1
38+ fi
39+ if [[ " $value " -lt 1 ]]; then
40+ echo " ERROR: ${name} must be >= 1, got '${value} '"
41+ exit 1
42+ fi
43+ }
44+
45+ get_operator_pid_with_retry () {
46+ local max_attempts=" ${1:- 5} "
47+ local attempt=1
48+ local pod_name=" "
49+ while [[ " $attempt " -le " $max_attempts " ]]; do
50+ pod_name=$( get_operator_pid)
51+ if [[ -n " $pod_name " ]]; then
52+ echo " $pod_name "
53+ return 0
54+ fi
55+ echo " Operator pod not found (attempt ${attempt} /${max_attempts} ); retrying in ${RETRY_DELAY_SECONDS} s..."
56+ sleep " $RETRY_DELAY_SECONDS "
57+ attempt=$(( attempt + 1 ))
58+ done
59+ return 1
60+ }
61+
2962get_rss_kb () {
3063 local pod=" $1 "
3164 # Read /proc/1/status from inside the container (PID 1 = operator process)
@@ -58,24 +91,77 @@ delete_nodes() {
5891 kubectl delete stellarnode " soak-node-${i} " -n " $TEST_NAMESPACE " \
5992 --ignore-not-found --wait=false
6093 done
61- # Wait for all to be gone before the next wave
62- kubectl wait stellarnode \
94+ # Wait for all to be gone before the next wave.
95+ if kubectl wait stellarnode \
6396 --for=delete \
6497 --all \
6598 -n " $TEST_NAMESPACE " \
66- --timeout=120s 2> /dev/null || true
99+ --timeout=" ${CLEANUP_TIMEOUT_SECONDS} s" 2> /dev/null; then
100+ echo " Cleanup finished within ${CLEANUP_TIMEOUT_SECONDS} s"
101+ return 0
102+ fi
103+
104+ local remaining
105+ remaining=$( kubectl get stellarnode -n " $TEST_NAMESPACE " --no-headers 2> /dev/null | wc -l | tr -d ' ' )
106+ echo " WARN: Cleanup timeout reached after ${CLEANUP_TIMEOUT_SECONDS} s with ${remaining} resource(s) still present."
107+ echo " Aborting soak loop because it is unsafe to proceed with leftover resources."
108+ return 1
67109}
68110
111+ cleanup_resources () {
112+ local reason=" ${1:- exit} "
113+ if [[ " $CLEANUP_DONE " == " true" ]]; then
114+ echo " [cleanup] Already completed (reason: ${reason} )"
115+ return
116+ fi
117+ CLEANUP_DONE=true
118+
119+ echo " [cleanup] Starting cleanup (reason: ${reason} )..."
120+ delete_nodes || true
121+ kubectl delete namespace " $TEST_NAMESPACE " --ignore-not-found --wait=false > /dev/null 2>&1 || true
122+ echo " [cleanup] Cleanup finished for namespace: ${TEST_NAMESPACE} "
123+ }
124+
125+ handle_exit () {
126+ local exit_code=$?
127+ cleanup_resources " exit"
128+ if [[ $exit_code -ne 0 ]]; then
129+ echo " [cleanup] Exiting with failure code: ${exit_code} "
130+ else
131+ echo " [cleanup] Exiting successfully"
132+ fi
133+ exit " $exit_code "
134+ }
135+
136+ handle_signal () {
137+ local signal_name=" $1 "
138+ local signal_code=1
139+ case " $signal_name " in
140+ INT) signal_code=130 ;;
141+ TERM) signal_code=143 ;;
142+ esac
143+ echo " [cleanup] Received ${signal_name} ; requesting graceful shutdown..."
144+ exit " $signal_code "
145+ }
146+
147+ trap ' handle_signal INT' INT
148+ trap ' handle_signal TERM' TERM
149+ trap ' handle_exit' EXIT
150+
69151# ── Setup ─────────────────────────────────────────────────────────────────────
70152
71153kubectl create namespace " $TEST_NAMESPACE " --dry-run=client -o yaml | kubectl apply -f -
72154
73- OPERATOR_POD=$( get_operator_pid)
155+ validate_positive_integer " RETRY_DELAY_SECONDS" " $RETRY_DELAY_SECONDS "
156+ echo " Retry delay: ${RETRY_DELAY_SECONDS} s"
157+
158+ OPERATOR_POD=$( get_operator_pid_with_retry 5)
74159if [[ -z " $OPERATOR_POD " ]]; then
75160 echo " ERROR: No stellar-operator pod found in namespace $OPERATOR_NAMESPACE "
76161 exit 1
77162fi
78163echo " Operator pod: $OPERATOR_POD "
164+ echo " Cleanup timeout: ${CLEANUP_TIMEOUT_SECONDS} s"
79165
80166# Baseline — let the operator settle for one sample interval first
81167sleep " $SAMPLE_INTERVAL "
@@ -99,7 +185,7 @@ while [[ $ELAPSED -lt $SOAK_DURATION ]]; do
99185 delete_nodes
100186
101187 # Sample memory after each wave (and on the fixed interval)
102- OPERATOR_POD=$( get_operator_pid )
188+ OPERATOR_POD=$( get_operator_pid_with_retry 5 )
103189 CURRENT_KB=$( get_rss_kb " $OPERATOR_POD " )
104190 GROWTH_KB=$(( CURRENT_KB - BASELINE_KB ))
105191 NOW=$( date +%s)
0 commit comments