Files
praxis/scripts/proxmox/health-check.sh
T
Praxis CI bb17615f41 feat(P01): SLICE-03+04 — PVE API layer (8 scripts) + health-check
SLICE-03 (devops-engineer): ported from coreci/scripts/proxmox/:
  api.sh (verbatim), ct-exists.sh, lxc-clone.sh (4GB/16GB, hostname=praxis),
  lxc-config.sh (praxis env vars, praxis-firstboot.sh snippet), lxc-start.sh,
  stage-snippet.sh (G-101 FIX: bakes GITEA_TOKEN into snippet via sed),
  timing.sh (verbatim), rollback.sh (proxy code removed)
SLICE-04 (devops-engineer): health-check.sh adapted for /health:8789
  (G-104 FIX: timeout bumped 300s→600s for Docker build margin)

REQ-DEPLOY-03, 04, 05, 07, 08 covered.

---ci---
project: praxis
phase: 1
milestone: v0.2
status: execute
slice: 03-04
wave: 2
---/ci---
2026-08-01 14:18:23 +00:00

70 lines
2.5 KiB
Bash
Executable File

#!/bin/sh
# Praxis — Poll a deployed LXC container's /health endpoint.
#
# Adapted from coreci/scripts/proxmox/health-check.sh.
# Coreci polls /healthz:18080; praxis polls /health:8789.
#
# If PRAXIS_HEALTH_URL is set, use it directly. Otherwise, query
# the Proxmox /interfaces endpoint for the CT's bridge IP and
# construct http://<ip>:<port>/health.
#
# Env: PROXMOX_API_URL, PROXMOX_API_TOKEN, PROXMOX_NODE,
# PRAXIS_HEALTH_URL (optional override), PRAXIS_PORT (default 8789),
# PRAXIS_HEALTH_TIMEOUT (default 600 — first-boot Docker build +
# compose up may take up to 5 min; G-104 FIX bumped from 300s to
# give margin vs the 5-min worst-case build time per RESEARCH.md Q7)
# Args: $1 = VMID
# Exit: 0 if healthy within timeout, 1 otherwise
set -eu
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# shellcheck source=api.sh disable=SC1091
. "${SCRIPT_DIR}/api.sh"
pve_env PROXMOX_API_URL PROXMOX_API_TOKEN PROXMOX_NODE
vmid="${1:?usage: health-check.sh <vmid>}"
http_port="${PRAXIS_PORT:-8789}"
timeout_s="${PRAXIS_HEALTH_TIMEOUT:-600}"
# Resolve health URL
if [ -n "${PRAXIS_HEALTH_URL:-}" ]; then
health_url="${PRAXIS_HEALTH_URL}"
else
# Query the CT's network interfaces for the bridge IP.
node="${PROXMOX_NODE}"
ifaces=$(pve_get "/nodes/${node}/lxc/${vmid}/interfaces" 2>/dev/null || true)
if [ -z "$ifaces" ] || [ "$ifaces" = "null" ]; then
echo "health-check: cannot resolve bridge IP for VMID ${vmid} (set PRAXIS_HEALTH_URL)" >&2
exit 1
fi
# Pick the first non-loopback IPv4 address. Emit only the IP fields
# (not hwaddr — it precedes .inet/.ip in PVE's response and head -1
# would pick the MAC — a bug fixed in coreci v3.6 P18 review).
ip=$(printf '%s' "$ifaces" | jq -r \
'.[] | select(.name != "lo") | (.inet? // .ip? // empty)' 2>/dev/null | grep -v '^$' | head -1)
if [ -z "$ip" ] || [ "$ip" = "null" ]; then
echo "health-check: no bridge IP found for VMID ${vmid} (set PRAXIS_HEALTH_URL)" >&2
exit 1
fi
health_url="http://${ip}:${http_port}/health"
fi
echo "health-check: polling ${health_url} for up to ${timeout_s}s..." >&2
ok=0
# shellcheck disable=SC2034
for i in $(seq 1 "$timeout_s"); do
if curl -fsS --connect-timeout 2 "$health_url" >/dev/null 2>&1; then
ok=1
break
fi
sleep 1
done
if [ "$ok" -ne 1 ]; then
echo "health-check: praxis did not become healthy within ${timeout_s}s at ${health_url}" >&2
exit 1
fi
echo "health-check: praxis healthy at ${health_url}" >&2