118 lines
3.6 KiB
Bash
Executable File
118 lines
3.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Smoke-test the /status and /metrics endpoints on a deployed boilerplate.
|
|
#
|
|
# Usage:
|
|
# METRICS_TOKEN=... scripts/observability/smoke-metrics.sh # uses staging defaults
|
|
# METRICS_TOKEN=... scripts/observability/smoke-metrics.sh https://api.example.com https://worker.example.com:9100 https://app.example.com
|
|
#
|
|
# Exits non-zero on the first failing assertion. Designed to run from CI
|
|
# after deploy and from the operator's laptop.
|
|
|
|
set -euo pipefail
|
|
|
|
API_BASE="${1:-https://api.boiler.saas-ctrl.com}"
|
|
WORKER_BASE="${2:-}"
|
|
WEB_BASE="${3:-https://app.boiler.saas-ctrl.com}"
|
|
|
|
if [ -z "${METRICS_TOKEN:-}" ]; then
|
|
echo "FAIL: METRICS_TOKEN env var is required." >&2
|
|
exit 2
|
|
fi
|
|
|
|
EXIT_CODE=0
|
|
|
|
probe_status() {
|
|
local label="$1"
|
|
local url="$2"
|
|
|
|
local response status body
|
|
response=$(curl --max-time 10 --silent --show-error --write-out '\n%{http_code}' "$url" || true)
|
|
status=$(printf '%s' "$response" | tail -n1)
|
|
body=$(printf '%s' "$response" | sed '$d')
|
|
|
|
if [ "$status" != "200" ] && [ "$status" != "503" ]; then
|
|
echo "FAIL: ${label} /status returned ${status} (expected 200 or 503)" >&2
|
|
echo "Body: ${body}" >&2
|
|
EXIT_CODE=1
|
|
return
|
|
fi
|
|
|
|
if ! printf '%s' "$body" | grep -q '"service":"' ; then
|
|
echo "FAIL: ${label} /status JSON missing service field" >&2
|
|
echo "Body: ${body}" >&2
|
|
EXIT_CODE=1
|
|
return
|
|
fi
|
|
|
|
echo "OK: ${label} /status (HTTP ${status})"
|
|
}
|
|
|
|
probe_metrics_unauth() {
|
|
local label="$1"
|
|
local url="$2"
|
|
|
|
local status
|
|
status=$(curl --max-time 10 --silent --output /dev/null --write-out '%{http_code}' "$url" || true)
|
|
if [ "$status" != "401" ] && [ "$status" != "404" ]; then
|
|
echo "FAIL: ${label} /metrics without token returned ${status} (expected 401 or 404)" >&2
|
|
EXIT_CODE=1
|
|
return
|
|
fi
|
|
echo "OK: ${label} /metrics without token (HTTP ${status})"
|
|
}
|
|
|
|
probe_metrics_authed() {
|
|
local label="$1"
|
|
local url="$2"
|
|
|
|
local response status body
|
|
response=$(curl --max-time 10 --silent --show-error -H "Authorization: Bearer ${METRICS_TOKEN}" \
|
|
--write-out '\n%{http_code}' "$url" || true)
|
|
status=$(printf '%s' "$response" | tail -n1)
|
|
body=$(printf '%s' "$response" | sed '$d')
|
|
|
|
if [ "$status" != "200" ]; then
|
|
echo "FAIL: ${label} /metrics returned ${status} (expected 200)" >&2
|
|
echo "Body (first 200 chars): $(printf '%s' "$body" | head -c 200)" >&2
|
|
EXIT_CODE=1
|
|
return
|
|
fi
|
|
|
|
for expected in "http_requests_total" "process_cpu_seconds_total"; do
|
|
if ! printf '%s' "$body" | grep -q "$expected" ; then
|
|
echo "FAIL: ${label} /metrics missing metric '${expected}'" >&2
|
|
EXIT_CODE=1
|
|
return
|
|
fi
|
|
done
|
|
|
|
echo "OK: ${label} /metrics (HTTP 200, expected metric names found)"
|
|
}
|
|
|
|
# API
|
|
probe_status "api" "${API_BASE}/status"
|
|
probe_metrics_unauth "api" "${API_BASE}/metrics"
|
|
probe_metrics_authed "api" "${API_BASE}/metrics"
|
|
|
|
# Web (uses /api/status + /api/metrics resource routes)
|
|
probe_status "web" "${WEB_BASE}/api/status"
|
|
probe_metrics_unauth "web" "${WEB_BASE}/api/metrics"
|
|
probe_metrics_authed "web" "${WEB_BASE}/api/metrics"
|
|
|
|
# Worker — only probed when the caller passed a URL (worker admin server is
|
|
# typically on a private network without TLS).
|
|
if [ -n "$WORKER_BASE" ]; then
|
|
probe_status "worker" "${WORKER_BASE}/status"
|
|
probe_metrics_unauth "worker" "${WORKER_BASE}/metrics"
|
|
probe_metrics_authed "worker" "${WORKER_BASE}/metrics"
|
|
else
|
|
echo "SKIP: worker /status + /metrics (pass a URL as the second positional arg to enable)"
|
|
fi
|
|
|
|
if [ $EXIT_CODE -eq 0 ]; then
|
|
echo "All smoke checks passed."
|
|
fi
|
|
|
|
exit $EXIT_CODE
|