rpki/scripts/02_self_check.sh
2026-07-14 14:44:40 +08:00

185 lines
5.0 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
SERVER_ENV_FILE="${ROOT_DIR}/deploy/server/.env"
CONSOLE_ENV_FILE="${ROOT_DIR}/deploy/console/.env"
SERVER_COMPOSE_FILE="${ROOT_DIR}/deploy/server/docker-compose.tcp.yml"
CONSOLE_COMPOSE_FILE="${ROOT_DIR}/deploy/console/docker-compose.yml"
SERVER_PROJECT="${RPKI_RTR_COMPOSE_PROJECT:-rpki-rtr}"
CONSOLE_PROJECT="${RPKI_CONSOLE_COMPOSE_PROJECT:-rpki-console}"
WAIT_SECS="${RPKI_SELF_CHECK_WAIT_SECS:-60}"
usage() {
cat <<'EOF'
Usage: scripts/02_self_check.sh [options]
Check whether the RTR server and console started by scripts/01_start.sh are healthy.
Options:
--wait SECS Wait timeout for each check. Default: 60
-h, --help Show this help.
EOF
}
log() {
printf '[02_self_check] %s\n' "$*" >&2
}
stage() {
printf '\n====== %s ======\n' "$*" >&2
}
die() {
printf '[02_self_check] ERROR: %s\n' "$*" >&2
exit 1
}
while [ "$#" -gt 0 ]; do
case "$1" in
--wait)
[ "$#" -ge 2 ] || die "--wait requires a value"
WAIT_SECS="$2"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
die "unknown option: $1"
;;
esac
done
command -v docker >/dev/null 2>&1 || die "docker command not found"
if docker compose version >/dev/null 2>&1; then
COMPOSE_BIN=(docker compose)
elif command -v docker-compose >/dev/null 2>&1 && docker-compose version >/dev/null 2>&1; then
COMPOSE_BIN=(docker-compose)
else
die "docker compose is not available"
fi
[ -f "${SERVER_ENV_FILE}" ] || die "server env file not found: ${SERVER_ENV_FILE}"
[ -f "${SERVER_COMPOSE_FILE}" ] || die "server compose file not found: ${SERVER_COMPOSE_FILE}"
[ -f "${CONSOLE_ENV_FILE}" ] || die "console env file not found: ${CONSOLE_ENV_FILE}"
[ -f "${CONSOLE_COMPOSE_FILE}" ] || die "console compose file not found: ${CONSOLE_COMPOSE_FILE}"
set -a
# shellcheck disable=SC1090
. "${SERVER_ENV_FILE}"
# shellcheck disable=SC1090
. "${CONSOLE_ENV_FILE}"
set +a
RTR_PORT="${RPKI_RTR_TCP_HOST_PORT:-323}"
ADMIN_PORT="${RPKI_RTR_ADMIN_ADDR##*:}"
ADMIN_PORT="${ADMIN_PORT:-8323}"
ADMIN_TOKEN="${RPKI_RTR_ADMIN_TOKEN:-}"
CONSOLE_PORT="${RPKI_CONSOLE_UI_PORT:-5173}"
server_compose() {
"${COMPOSE_BIN[@]}" --env-file "${SERVER_ENV_FILE}" -p "${SERVER_PROJECT}" -f "${SERVER_COMPOSE_FILE}" "$@"
}
console_compose() {
"${COMPOSE_BIN[@]}" --env-file "${CONSOLE_ENV_FILE}" -p "${CONSOLE_PROJECT}" -f "${CONSOLE_COMPOSE_FILE}" "$@"
}
container_running() {
local compose_kind="$1"
local service="$2"
local cid state
if [ "${compose_kind}" = "server" ]; then
cid="$(server_compose ps -q "${service}" 2>/dev/null || true)"
else
cid="$(console_compose ps -q "${service}" 2>/dev/null || true)"
fi
[ -n "${cid}" ] || return 1
state="$(docker inspect -f '{{.State.Running}}' "${cid}" 2>/dev/null || true)"
[ "${state}" = "true" ]
}
tcp_open() {
local host="$1"
local port="$2"
if command -v nc >/dev/null 2>&1; then
nc -z "${host}" "${port}" >/dev/null 2>&1
return
fi
(exec 3<>"/dev/tcp/${host}/${port}") >/dev/null 2>&1
}
http_get() {
local url="$1"
local token="${2:-}"
if command -v curl >/dev/null 2>&1; then
if [ -n "${token}" ]; then
curl -fsS -H "Authorization: Bearer ${token}" "${url}"
else
curl -fsS "${url}"
fi
return
fi
die "curl command is required for HTTP health checks"
}
wait_until() {
local label="$1"
shift
local deadline=$((SECONDS + WAIT_SECS))
while [ "${SECONDS}" -lt "${deadline}" ]; do
if "$@"; then
log "${label}: ok"
return 0
fi
sleep 1
done
die "${label}: failed after ${WAIT_SECS}s"
}
show_command() {
printf '[02_self_check] check command: %s\n' "$*" >&2
}
check_admin_health() {
local body
body="$(http_get "http://127.0.0.1:${ADMIN_PORT}/admin/rtr/health" "${ADMIN_TOKEN}" 2>/dev/null || true)"
printf '%s' "${body}" | grep -q '"status"[[:space:]]*:[[:space:]]*"ok"'
}
check_console_http() {
http_get "http://127.0.0.1:${CONSOLE_PORT}/" >/dev/null 2>&1
}
stage "Checking Containers"
show_command "${COMPOSE_BIN[*]} --env-file ${SERVER_ENV_FILE} -p ${SERVER_PROJECT} -f ${SERVER_COMPOSE_FILE} ps -q rpki-rtr && docker inspect"
wait_until "server container" container_running server rpki-rtr
show_command "${COMPOSE_BIN[*]} --env-file ${CONSOLE_ENV_FILE} -p ${CONSOLE_PROJECT} -f ${CONSOLE_COMPOSE_FILE} ps -q rpki-console-ui && docker inspect"
wait_until "console container" container_running console rpki-console-ui
stage "Checking Server"
show_command "tcp connect 127.0.0.1:${RTR_PORT}"
wait_until "RTR port ${RTR_PORT}" tcp_open 127.0.0.1 "${RTR_PORT}"
show_command "curl -fsS -H 'Authorization: Bearer <token>' http://127.0.0.1:${ADMIN_PORT}/admin/rtr/health"
wait_until "Admin health" check_admin_health
stage "Checking Console"
show_command "tcp connect 127.0.0.1:${CONSOLE_PORT}"
wait_until "Console port ${CONSOLE_PORT}" tcp_open 127.0.0.1 "${CONSOLE_PORT}"
show_command "curl -fsS http://127.0.0.1:${CONSOLE_PORT}/"
wait_until "Console HTTP" check_console_http
stage "Self-Check Passed"