#!/usr/bin/env bash # check_monitoring_pages.sh — verify public monitoring HTML pages via FQDN # # Outside-in: curl https://// and require a real HTML monitoring page. # Catches: merchant JSON code 21 (Caddy handle missing), WP 404, empty stubs, deploy skip. # # Env (same knobs as host-agent HTML layout): # MON_HOSTS space-separated FQDNs (default from TALER_DOMAIN) # HTML_URL_OK path for OK page (default /monitoring/) # HTML_URL_ERR optional err path; checked if MONPAGES_CHECK_ERR=1 # MONITORING_PAGE_URLS optional full URL list (overrides host+path construction) # MONPAGES_EXTRA_URLS additional absolute URLs (space-separated) # TIMEOUT curl timeout (from lib.sh) # MONPAGES_STAGING_BASE / HTML_OUT optional staging root for diagnosis # HTML_OK_DIR staging subdir (default monitoring) # set -euo pipefail ROOT=$(cd "$(dirname "$0")" && pwd) # shellcheck source=lib.sh source "$ROOT/lib.sh" set_area monpages section "monpages · public monitoring HTML via FQDN (outside-in)" # MONPAGES_REQUIRE_PUBLIC=0 → missing public pages are WARN (staging-only stacks / FP until vhost) : "${MONPAGES_REQUIRE_PUBLIC:=1}" # Default hosts from domain (mirror run-host-report.sh) if [ -z "${MON_HOSTS:-}" ]; then case "${TALER_DOMAIN:-}" in hacktivism.ch|koopa) MON_HOSTS="bank.hacktivism.ch exchange.hacktivism.ch taler.hacktivism.ch" ;; stage.lefrancpaysan.ch|stage.*lefrancpaysan*) MON_HOSTS="stage.bank.lefrancpaysan.ch stage.exchange.lefrancpaysan.ch stage.monnaie.lefrancpaysan.ch" ;; lefrancpaysan.ch) MON_HOSTS="bank.lefrancpaysan.ch exchange.lefrancpaysan.ch monnaie.lefrancpaysan.ch" ;; *) MON_HOSTS="${TALER_DOMAIN:-}" ;; esac fi HTML_URL_OK="${HTML_URL_OK:-/monitoring/}" HTML_URL_ERR="${HTML_URL_ERR:-/monitoring_err/}" # ensure leading + trailing slash case "$HTML_URL_OK" in /*) ;; *) HTML_URL_OK="/$HTML_URL_OK" ;; esac case "$HTML_URL_OK" in */) ;; *) HTML_URL_OK="${HTML_URL_OK}/" ;; esac build_urls() { local h p if [ -n "${MONITORING_PAGE_URLS:-}" ]; then # shellcheck disable=SC2086 printf '%s\n' $MONITORING_PAGE_URLS else for h in $MON_HOSTS; do [ -z "$h" ] && continue printf 'https://%s%s\n' "$h" "$HTML_URL_OK" if [ "${MONPAGES_CHECK_ERR:-0}" = "1" ]; then p="$HTML_URL_ERR" case "$p" in /*) ;; *) p="/$p" ;; esac case "$p" in */) ;; *) p="${p}/" ;; esac printf 'https://%s%s\n' "$h" "$p" fi done fi if [ -n "${MONPAGES_EXTRA_URLS:-}" ]; then # shellcheck disable=SC2086 printf '%s\n' $MONPAGES_EXTRA_URLS fi } # True if body looks like our monitoring HTML (not merchant API / WP 404). is_monitoring_html() { local f="$1" if grep -qE '"code"[[:space:]]*:[[:space:]]*21' "$f" 2>/dev/null; then return 1 fi if grep -qiE 'There is no endpoint defined for the URL' "$f" 2>/dev/null; then return 1 fi if grep -qiE 'wp-content|wordpress' "$f" 2>/dev/null \ && grep -qiE '404|not found|page introuvable' "$f" 2>/dev/null; then return 1 fi if grep -qE 'sticky-bar|version-link|taler-monitoring|class="sticky' "$f" 2>/dev/null; then return 0 fi if head -c 4096 "$f" | grep -qiE '/dev/null; then return 0 fi if head -c 512 "$f" | grep -qiE '/dev/null || echo 000) if _is_bare_url "$url" && [ "${MONPAGES_BARE_STRICT:-0}" != "1" ]; then soft=1 fi if grep -qE '"code"[[:space:]]*:[[:space:]]*21' "$body" 2>/dev/null \ || grep -qiE 'There is no endpoint defined for the URL' "$body" 2>/dev/null; then if [ "$soft" = "1" ]; then warn "public mon page bare URL" \ "$url -> HTTP $code code 21 (prefer trailing slash; set MONPAGES_BARE_STRICT=1 to ERROR)" rm -f "$body" return 0 fi _mon_fail_or_soft "public mon page missing" \ "$url -> HTTP $code merchant/API JSON code 21 (publish HTML + reverse-proxy handle /monitoring*)" || { rm -f "$body"; return 1; } rm -f "$body" return 0 fi if [ "$code" != "200" ]; then if [ "$soft" = "1" ]; then warn "public mon page bare URL" "$url -> HTTP $code (prefer trailing slash form)" rm -f "$body" return 0 fi _mon_fail_or_soft "public mon page" "$url -> HTTP $code (want 200 HTML)" || { rm -f "$body"; return 1; } rm -f "$body" return 0 fi if is_monitoring_html "$body"; then if grep -qE 'sticky-bar|version-link' "$body" 2>/dev/null; then ok "public mon page" "$url -> HTTP 200 monitoring HTML" else warn "public mon page" "$url -> HTTP 200 HTML but weak markers (stub/bootstrap?)" fi rm -f "$body" return 0 fi hint=$(head -c 120 "$body" | tr '\n' ' ' | tr -cd '[:print:] ') _mon_fail_or_soft "public mon page not monitoring HTML" "$url -> HTTP 200 body!=suite (${hint}...)" || { rm -f "$body"; return 1; } rm -f "$body" return 0 } URLS=() while IFS= read -r line; do [ -n "$line" ] || continue # dedupe skip=0 for e in "${URLS[@]+"${URLS[@]}"}"; do [ "$e" = "$line" ] && skip=1 && break done [ "$skip" = "1" ] && continue URLS+=("$line") done < <(build_urls) # Bare URLs without trailing slash: optional soft check (default on). # Many reverse proxies only redirect /monitoring → /monitoring/; bare may hit the app (code 21). # MONPAGES_CHECK_BARE=0 → skip bare entirely # MONPAGES_BARE_STRICT=1 → bare failures are ERROR (default: WARN if slash form exists) if [ "${MONPAGES_CHECK_BARE:-1}" = "1" ]; then _extra=() for u in "${URLS[@]}"; do case "$u" in */) _bare=${u%/}; [ -n "$_bare" ] && _extra+=("$_bare") ;; esac done for u in "${_extra[@]+"${_extra[@]}"}"; do skip=0 for e in "${URLS[@]+"${URLS[@]}"}"; do [ "$e" = "$u" ] && skip=1 && break done [ "$skip" = "1" ] && continue URLS+=("$u") # mark bare for soft handling via env list MONPAGES_BARE_URLS="${MONPAGES_BARE_URLS:-} $u" done export MONPAGES_BARE_URLS fi if [ "${#URLS[@]}" -eq 0 ]; then fail "monpages" "no URLs to check (set MON_HOSTS or MONITORING_PAGE_URLS)" exit 1 fi echo " checking ${#URLS[@]} URL(s) via FQDN..." ec=0 for u in "${URLS[@]}"; do check_one "$u" || ec=1 done if [ "$ec" -ne 0 ]; then echo " hint: public monitoring HTML not served (404 / merchant code 21)" echo " publish staging HTML + configure reverse-proxy/Caddy handle for /monitoring*" echo " (on koopa: sudo ~/koopa-caddy/apply-monitoring-live.sh)" # Staging vs public diagnosis (host-agent sets MONPAGES_STAGING_BASE / HTML_OUT) _stg="${MONPAGES_STAGING_BASE:-${HTML_OUT:-${HTML_BASE:-$HOME/monitoring-sites-staging}}}" _ok_dir="${HTML_OK_DIR:-monitoring}" if [ -n "${MON_HOSTS:-}" ] && [ -n "$_stg" ]; then for _h in $MON_HOSTS; do _f="$_stg/$_h/${_ok_dir}/index.html" if [ -f "$_f" ]; then echo " staging OK: $_f ($(wc -c <"$_f" | tr -d " ") bytes) — not published/served" else echo " staging missing: $_f" fi done fi _www="${DEPLOY_WWW_ROOT:-/var/www/monitoring-sites}" if [ -e "$_www" ] && [ ! -w "$_www" ]; then echo " DEPLOY_WWW_ROOT=$_www not writable by $(id -un 2>/dev/null || echo user)" fi fi exit "$ec"