#!/bin/bash # Stalwart upgrade verifier. # --------------------------------------------------------------------------- # Stalwart publishes Kubernetes-style probes on its admin port (8080): # GET /healthz/live — the process is alive and not deadlocked # GET /healthz/ready — dependencies initialised, config loaded, accepting traffic # https://stalw.art/docs/http/overview/ # # Readiness is the one that matters after a version move: it only answers 200 # once the storage backend is open and the config has loaded, which is exactly # the window where a schema change would otherwise go unnoticed. Liveness alone # would pass on a process that is up but unable to serve. # # Deliberately weaker than the Nextcloud verifier: Stalwart's probes confirm the # server is serving, but do not report a version, so this asserts readiness # rather than "running exactly $expected". Stated plainly instead of implied — # the ladder is only ever as strong as the check underneath it, and pretending # otherwise is how a half-migrated app advances a rung. # stalwart_upgrade_verify # 0 only when /healthz/ready answers 200 and keeps answering it. stalwart_upgrade_verify() { local app="$1" expected="$2" deadline="$3" local stable=0 stable_needed=3 last="" while [ "$(date +%s)" -lt "$deadline" ]; do local code code="$(runFileOp docker exec stalwart-service curl -fsS -o /dev/null -w '%{http_code}' \ --max-time 5 http://localhost:8080/healthz/ready 2>/dev/null | tr -d '\r')" last="healthz/ready=${code:-none}" if [ "$code" = "200" ]; then stable=$((stable + 1)) # Ready must HOLD: a server that flaps ready/not-ready is mid-restart, # and one lucky 200 is not evidence the upgrade settled. if (( stable >= stable_needed )); then isSuccessful "Stalwart is ready (readiness probe stable) after moving to $expected." return 0 fi else stable=0 fi sleep 5 done isError "Stalwart did not report ready for $expected before the deadline.${last:+ Last probe: $last}" return 1 }