monitoring: stage.lefrancpaysan like hacktivism (inside+versions via stagepaysan)
Expand default phases for TESTPAYSAN to urls + inside + versions + e2e. Inside/version/load use low-priv francpaysan-stage-user (stagepaysan) and stage-lfp-* containers on 9030–9032; public stats.json stays outside-in.
This commit is contained in:
parent
19bbcc09da
commit
08c55e71a7
7 changed files with 398 additions and 48 deletions
|
|
@ -81,12 +81,18 @@ Each check prints **global** and **grouped** ids:
|
|||
./taler-monitoring.sh sanity
|
||||
./taler-monitoring.sh e2e
|
||||
|
||||
# FrancPaysan STAGE (TESTPAYSAN) — default: urls + e2e (withdraw + pay templates)
|
||||
# FrancPaysan STAGE (TESTPAYSAN) — like hacktivism breadth:
|
||||
# default phases: urls + inside + versions + e2e
|
||||
./taler-monitoring.sh -d stage.lefrancpaysan.ch
|
||||
# Admin credit: E2E_BANK_ADMIN_PASS=… or SSH francpaysan-host secrets
|
||||
./taler-monitoring.sh -d stage.lefrancpaysan.ch inside # stagepaysan only
|
||||
# inside: low-priv SSH francpaysan-stage-user (User stagepaysan) → podman
|
||||
# containers stage-lfp-{bank,exchange-ansible,merchant} · ports 9032/9031/9030
|
||||
# stats: outside-in public …/intro/stats.json (age via generated_at_unix)
|
||||
# Admin credit for e2e: E2E_BANK_ADMIN_PASS=… or francpaysan-host secrets
|
||||
# (bank-admin-password.txt under /mnt/data/stagepaysan/bank/secrets/)
|
||||
# Override: INSIDE_SSH=… INSIDE_PROFILE=stage-lfp
|
||||
|
||||
# Other domains — public HTTPS only, never SSH (pass e2e explicitly)
|
||||
# Other domains — public HTTPS only (pass e2e/inside explicitly)
|
||||
./taler-monitoring.sh -d taler.net
|
||||
./taler-monitoring.sh --domain taler-ops.ch
|
||||
./taler-monitoring.sh -d my.taler-ops.ch urls
|
||||
|
|
@ -165,13 +171,18 @@ Helpers in `lib.sh`: `set_taler_stack`, `load_domain_profile`, `apply_taler_doma
|
|||
| `taler.net` / `demo.taler.net` | bank.demo.taler.net | exchange.demo.taler.net | backend.demo.taler.net | KUDOS |
|
||||
| `test.taler.net` | bank.test… | exchange.test… | backend.test… | **TESTKUDOS** · no landings |
|
||||
| `lefrancpaysan.ch` | bank.… | exchange.… | **monnaie.…** (merchant) | report-only · no landings |
|
||||
| **`stage.lefrancpaysan.ch`** | stage.bank.… | stage.exchange.… | **stage.monnaie.…** | **TESTPAYSAN** · landings · **inside via stagepaysan** |
|
||||
| `taler-ops.ch` / `my.taler-ops.ch` | bank.taler-ops.ch | exchange.taler-ops.ch | **my.taler-ops.ch** | CHF · **no landings** |
|
||||
| `stage.taler-ops.ch` | bank.stage… | exchange.stage… | **my.stage…** | CHF · **no landings** |
|
||||
| unknown | bank.DOMAIN | exchange.DOMAIN | my.DOMAIN then probe | any · no landings |
|
||||
|
||||
**Landings:** only GOA (and optionally demo) use public `/intro` pages. **taler-ops.ch does not** — `CHECK_LANDING=0` in the profile skips intro crawl, shop assets, and demo-withdraw checks.
|
||||
**Landings:** GOA, stage LFP (`TESTPAYSAN`), and optionally demo use public `/intro` pages. **taler-ops.ch does not** — `CHECK_LANDING=0` skips intro crawl.
|
||||
|
||||
**SSH only for koopa** (`hacktivism.ch` / `-d koopa`).
|
||||
**SSH:**
|
||||
| Stack | Host alias | User | Scope |
|
||||
|-------|------------|------|--------|
|
||||
| koopa / hacktivism | `koopa` | hernani | full host + containers |
|
||||
| stage LFP | `francpaysan-stage-user` | **stagepaysan** | own podman only (no sudo / no prod data) |
|
||||
|
||||
Other domains: never SSH. Optional **e2e** aborts cleanly on login/KYC.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
#!/usr/bin/env bash
|
||||
# Inside status for bank / exchange / merchant. Hard-capped SSH — never hang forever.
|
||||
# Inside status for bank / exchange / merchant containers.
|
||||
# Profiles:
|
||||
# koopa (default LOCAL_STACK=1) — SSH KOOPA_SSH, containers taler-hacktivism*
|
||||
# stage-lfp (TESTPAYSAN) — SSH INSIDE_SSH (francpaysan-stage-user / stagepaysan),
|
||||
# low-priv podman only; ports 9030–9032; stats remain outside-in (urls).
|
||||
set -euo pipefail
|
||||
ROOT=$(cd "$(dirname "$0")" && pwd)
|
||||
# shellcheck source=lib.sh
|
||||
|
|
@ -7,14 +11,250 @@ source "$ROOT/lib.sh"
|
|||
# shellcheck source=metrics.sh
|
||||
source "$ROOT/metrics.sh"
|
||||
|
||||
# Area inside.* — container / process state on koopa (SSH)
|
||||
# Groups: inside.ssh / inside.bank / inside.exchange / inside.merchant / inside.caddy
|
||||
set_area inside
|
||||
set_group ssh
|
||||
|
||||
PROFILE="${INSIDE_PROFILE:-}"
|
||||
if [ -z "$PROFILE" ]; then
|
||||
if [ "${LOCAL_STACK:-0}" = "1" ]; then
|
||||
PROFILE=koopa
|
||||
elif [ "${EXPECT_CURRENCY:-}" = "TESTPAYSAN" ] || [ -n "${INSIDE_SSH:-}" ]; then
|
||||
PROFILE=stage-lfp
|
||||
else
|
||||
PROFILE=koopa
|
||||
fi
|
||||
fi
|
||||
|
||||
section "inside · collect (${PROFILE})"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# stage-lfp: low-priv stagepaysan on francpaysan-host
|
||||
# ---------------------------------------------------------------------------
|
||||
if [ "$PROFILE" = "stage-lfp" ]; then
|
||||
SSH_HOST="${INSIDE_SSH:-francpaysan-stage-user}"
|
||||
BANK_CTR="${INSIDE_BANK_CTR:-stage-lfp-bank}"
|
||||
EX_CTR="${INSIDE_EXCHANGE_CTR:-stage-lfp-exchange-ansible}"
|
||||
MER_CTR="${INSIDE_MERCHANT_CTR:-stage-lfp-merchant}"
|
||||
BANK_PORT="${INSIDE_BANK_PORT:-9032}"
|
||||
EX_PORT="${INSIDE_EXCHANGE_PORT:-9031}"
|
||||
MER_PORT="${INSIDE_MERCHANT_PORT:-9030}"
|
||||
DNS_BANK="${INSIDE_DNS_BANK:-stage.bank.lefrancpaysan.ch}"
|
||||
DNS_EX="${INSIDE_DNS_EXCHANGE:-stage.exchange.lefrancpaysan.ch}"
|
||||
DNS_MER="${INSIDE_DNS_MERCHANT:-stage.monnaie.lefrancpaysan.ch}"
|
||||
# Stage remote has more podman execs than koopa; allow a bit more wall time
|
||||
STAGE_SSH_T="${INSIDE_SSH_TIMEOUT:-${SSH_CMD_TIMEOUT:-24}}"
|
||||
if [ "${STAGE_SSH_T}" -lt 24 ] 2>/dev/null; then STAGE_SSH_T=24; fi
|
||||
|
||||
if ! mon_ssh_ok "$SSH_HOST"; then
|
||||
err "ssh" "cannot reach ${SSH_HOST} (stagepaysan low-priv) — set INSIDE_SSH= or SKIP"
|
||||
summary
|
||||
exit 1
|
||||
fi
|
||||
ok "ssh ${SSH_HOST}" "stagepaysan (podman, no sudo)"
|
||||
|
||||
# Inject names/ports into remote (ssh bash -s does not inherit local env).
|
||||
RAW=$(
|
||||
{
|
||||
printf 'BANK_CTR=%q; EX_CTR=%q; MER_CTR=%q\n' "$BANK_CTR" "$EX_CTR" "$MER_CTR"
|
||||
printf 'BANK_PORT=%q; EX_PORT=%q; MER_PORT=%q\n' "$BANK_PORT" "$EX_PORT" "$MER_PORT"
|
||||
printf 'DNS_BANK=%q; DNS_EX=%q; DNS_MER=%q\n' "$DNS_BANK" "$DNS_EX" "$DNS_MER"
|
||||
cat <<'REMOTE'
|
||||
set +e
|
||||
emit() { printf 'E|%s|%s|%s|%s\n' "$1" "$2" "$3" "$(printf '%s' "${4:-}" | tr '\n\r' ' ' | head -c 200)"; }
|
||||
hc() { curl -skS -m 3 -o /tmp/mb -w '%{http_code}' "$1" 2>/dev/null || echo 000; }
|
||||
hasp() { podman exec "$1" pgrep -f "$2" >/dev/null 2>&1; }
|
||||
|
||||
BANK="${BANK_CTR}"
|
||||
EX="${EX_CTR}"
|
||||
MER="${MER_CTR}"
|
||||
podman ps --format '{{.Names}}' 2>/dev/null | grep -qx "$BANK" || BANK=$(podman ps --format '{{.Names}}' 2>/dev/null | grep -iE 'stage.*bank|lfp-bank' | head -1)
|
||||
podman ps --format '{{.Names}}' 2>/dev/null | grep -qx "$EX" || EX=$(podman ps --format '{{.Names}}' 2>/dev/null | grep -iE 'stage.*exchange|lfp-exchange' | head -1)
|
||||
podman ps --format '{{.Names}}' 2>/dev/null | grep -qx "$MER" || MER=$(podman ps --format '{{.Names}}' 2>/dev/null | grep -iE 'stage.*merchant|lfp-merchant' | head -1)
|
||||
|
||||
check_dns() {
|
||||
local comp="$1" ctr="$2" host="$3"
|
||||
local line ip code
|
||||
[ -n "$host" ] || { emit "$comp" WARN "dns" "empty host"; return 1; }
|
||||
line=$(podman exec "$ctr" getent ahostsv4 "$host" 2>/dev/null | head -1)
|
||||
[ -z "$line" ] && line=$(podman exec "$ctr" getent hosts "$host" 2>/dev/null | head -1)
|
||||
ip=$(echo "$line" | awk '{print $1}')
|
||||
if [ -z "$ip" ]; then
|
||||
emit "$comp" WARN "dns $host" "no resolve inside container"
|
||||
return 1
|
||||
fi
|
||||
if [ "$ip" = "127.0.0.1" ] || [ "$ip" = "::1" ]; then
|
||||
emit "$comp" WARN "dns $host" "$ip (loopback)"
|
||||
return 1
|
||||
fi
|
||||
# 169.254.x = pasta host-gateway pin is OK for stage
|
||||
code=$(podman exec "$ctr" curl -skS -m 3 -o /dev/null -w '%{http_code}' "https://${host}/config" 2>/dev/null || echo 000)
|
||||
if [ "$code" = "200" ]; then
|
||||
emit "$comp" OK "dns $host" "→ $ip /config=$code"
|
||||
else
|
||||
emit "$comp" WARN "dns $host" "→ $ip /config=$code"
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -z "$BANK" ]; then emit bank ERROR container "not running"
|
||||
else
|
||||
emit bank INFO container "$(podman ps --filter name=^${BANK}$ --format '{{.Names}} {{.Status}}' | head -1)"
|
||||
emit bank INFO ports "$(podman ps --filter name=^${BANK}$ --format '{{.Ports}}' | head -1)"
|
||||
hasp "$BANK" 'MainKt serve|libeufin-bank serve' && emit bank OK libeufin "running" || emit bank ERROR libeufin "not running"
|
||||
podman exec "$BANK" pg_isready -q 2>/dev/null && emit bank OK postgres "ready" || emit bank WARN postgres "pg_isready failed"
|
||||
c=$(hc "http://127.0.0.1:${BANK_PORT}/config")
|
||||
[ "$c" = "200" ] && emit bank OK "host :${BANK_PORT}/config" "HTTP $c" || emit bank ERROR "host :${BANK_PORT}/config" "HTTP $c"
|
||||
c=$(hc "http://127.0.0.1:${BANK_PORT}/taler-integration/config")
|
||||
[ "$c" = "200" ] && emit bank OK "host integration" "HTTP $c" || emit bank ERROR "host integration" "HTTP $c"
|
||||
check_dns bank "$BANK" "$DNS_BANK" || true
|
||||
check_dns bank "$BANK" "$DNS_EX" || true
|
||||
fi
|
||||
|
||||
if [ -z "$EX" ]; then emit exchange ERROR container "not running"
|
||||
else
|
||||
emit exchange INFO container "$(podman ps --filter name=^${EX}$ --format '{{.Names}} {{.Status}}' | head -1)"
|
||||
c=$(hc "http://127.0.0.1:${EX_PORT}/config")
|
||||
[ "$c" = "200" ] && emit exchange OK "host :${EX_PORT}/config" "HTTP $c" || emit exchange ERROR "host :${EX_PORT}/config" "HTTP $c"
|
||||
c=$(curl -sS -m 5 -o /dev/null -w '%{http_code}' "http://127.0.0.1:${EX_PORT}/keys" 2>/dev/null || echo 000)
|
||||
[ "$c" = "200" ] && emit exchange OK "host :${EX_PORT}/keys" "HTTP $c" || emit exchange ERROR "host :${EX_PORT}/keys" "HTTP $c"
|
||||
hasp "$EX" 'taler-exchange-httpd' && emit exchange OK httpd "running" || emit exchange ERROR httpd "not running"
|
||||
hasp "$EX" 'taler-exchange-wirewatch' && emit exchange OK wirewatch "running" || emit exchange ERROR wirewatch "not running"
|
||||
hasp "$EX" 'taler-exchange-aggregator' && emit exchange OK aggregator "running" || emit exchange WARN aggregator "not running"
|
||||
hasp "$EX" 'taler-exchange-transfer' && emit exchange OK transfer "running" || emit exchange WARN transfer "not running"
|
||||
check_dns exchange "$EX" "$DNS_BANK" || true
|
||||
check_dns exchange "$EX" "$DNS_EX" || true
|
||||
check_dns exchange "$EX" "$DNS_MER" || true
|
||||
fi
|
||||
|
||||
if [ -z "$MER" ]; then emit merchant ERROR container "not running"
|
||||
else
|
||||
emit merchant INFO container "$(podman ps --filter name=^${MER}$ --format '{{.Names}} {{.Status}}' | head -1)"
|
||||
c=$(hc "http://127.0.0.1:${MER_PORT}/config")
|
||||
[ "$c" = "200" ] && emit merchant OK "host :${MER_PORT}/config" "HTTP $c" || emit merchant ERROR "host :${MER_PORT}/config" "HTTP $c"
|
||||
hasp "$MER" 'taler-merchant-httpd' && emit merchant OK httpd "running" || emit merchant ERROR httpd "not running"
|
||||
# Stage merchant often has no wirewatch unit — INFO not WARN
|
||||
hasp "$MER" 'taler-merchant-wirewatch' && emit merchant OK wirewatch "running" || emit merchant INFO wirewatch "not running (optional on stage)"
|
||||
hasp "$MER" 'taler-merchant-depositcheck' && emit merchant OK depositcheck "running" || emit merchant INFO depositcheck "not running (optional on stage)"
|
||||
hasp "$MER" 'taler-merchant-exchangekeyupdate' && emit merchant OK exchangekeyupdate "running" || emit merchant INFO exchangekeyupdate "not running"
|
||||
check_dns merchant "$MER" "$DNS_BANK" || true
|
||||
check_dns merchant "$MER" "$DNS_EX" || true
|
||||
check_dns merchant "$MER" "$DNS_MER" || true
|
||||
fi
|
||||
|
||||
# Caddy is host-wide (often root); stagepaysan can only see the process
|
||||
if pgrep -x caddy >/dev/null 2>&1; then
|
||||
emit caddy OK process "running (host)"
|
||||
else
|
||||
emit caddy WARN process "not seen as stagepaysan (may still run as root)"
|
||||
fi
|
||||
|
||||
echo DONE
|
||||
REMOTE
|
||||
} | mon_ssh_bash "$SSH_HOST" "${STAGE_SSH_T}" || true
|
||||
)
|
||||
|
||||
if [ -z "$RAW" ] || ! echo "$RAW" | grep -q '^E|'; then
|
||||
err "ssh" "stage remote timed out or empty (cap ${STAGE_SSH_T}s · host=${SSH_HOST})"
|
||||
summary
|
||||
exit 1
|
||||
fi
|
||||
|
||||
_last_inside_grp=""
|
||||
while IFS= read -r line; do
|
||||
case "$line" in
|
||||
E\|*)
|
||||
IFS='|' read -r _ comp level key detail <<<"$line"
|
||||
case "$comp" in
|
||||
bank|exchange|merchant|caddy) _g="$comp" ;;
|
||||
*) _g="ssh" ;;
|
||||
esac
|
||||
if [ "$_g" != "$_last_inside_grp" ]; then
|
||||
set_group "$_g"
|
||||
_last_inside_grp="$_g"
|
||||
fi
|
||||
case "$level" in
|
||||
OK) ok "[$comp] $key${detail:+ ($detail)}" ;;
|
||||
ERROR) err "$comp" "$key" "$detail" ;;
|
||||
WARN) warn "[$comp] $key" "$detail" ;;
|
||||
INFO) info "[$comp] $key" "$detail" ;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
done <<<"$RAW"
|
||||
|
||||
# Stats from outside (laptop) — public HTTPS, no stagepaysan write needed
|
||||
set_group stats
|
||||
section "inside · public stats (outside-in)"
|
||||
_probe_public_stats() {
|
||||
local comp="$1" url="$2"
|
||||
local body code age unix now
|
||||
body=$(mktemp)
|
||||
code=$(curl -skS -m 8 -o "$body" -w '%{http_code}' "$url" 2>/dev/null || echo 000)
|
||||
if [ "$code" != "200" ]; then
|
||||
warn "[$comp] public stats.json" "HTTP $code · $url"
|
||||
rm -f "$body"
|
||||
return
|
||||
fi
|
||||
unix=$(python3 -c 'import json,sys; d=json.load(open(sys.argv[1])); print(d.get("generated_at_unix") or 0)' "$body" 2>/dev/null || echo 0)
|
||||
now=$(date +%s)
|
||||
if [ "${unix:-0}" -gt 0 ] 2>/dev/null; then
|
||||
age=$((now - unix))
|
||||
if [ "$age" -lt 0 ]; then age=0; fi
|
||||
if [ "$age" -le "${STATS_STALE_SECS:-900}" ]; then
|
||||
ok "[$comp] public stats.json" "HTTP 200 age=${age}s · $url"
|
||||
elif [ "$age" -le "${STATS_FAIL_SECS:-3600}" ]; then
|
||||
warn "[$comp] public stats.json" "stale age=${age}s · $url"
|
||||
else
|
||||
err "$comp" "public stats.json" "too old age=${age}s · $url"
|
||||
fi
|
||||
else
|
||||
ok "[$comp] public stats.json" "HTTP 200 · $url"
|
||||
fi
|
||||
rm -f "$body"
|
||||
}
|
||||
_probe_public_stats bank "https://${DNS_BANK}/intro/stats.json"
|
||||
_probe_public_stats exchange "https://${DNS_EX}/intro/stats.json"
|
||||
_probe_public_stats merchant "https://${DNS_MER}/intro/stats.json"
|
||||
|
||||
# Host load as stagepaysan (no container RSS from koopa metrics)
|
||||
set_group load
|
||||
section "inside · load (stagepaysan host)"
|
||||
LOAD_LINE=$(mon_ssh_bash "$SSH_HOST" 8 <<'EOF' || true
|
||||
python3 - <<'PY'
|
||||
import os
|
||||
la=os.getloadavg()
|
||||
print("loadavg=%.2f,%.2f,%.2f" % la)
|
||||
try:
|
||||
with open("/proc/meminfo") as f:
|
||||
d={}
|
||||
for line in f:
|
||||
k,v=line.split(":")[0], line.split(":")[1].strip().split()[0]
|
||||
d[k]=int(v)
|
||||
total=d.get("MemTotal",0)/1024/1024
|
||||
avail=d.get("MemAvailable",0)/1024/1024
|
||||
used=total-avail
|
||||
print("mem_used=%.2fGiB avail=%.2fGiB total=%.2fGiB" % (used, avail, total))
|
||||
except Exception:
|
||||
print("mem=?")
|
||||
PY
|
||||
EOF
|
||||
)
|
||||
if [ -n "$LOAD_LINE" ]; then
|
||||
info "stage host" "$(echo "$LOAD_LINE" | tr '\n' ' ')"
|
||||
else
|
||||
info "stage host" "load probe empty"
|
||||
fi
|
||||
|
||||
summary
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# koopa (default) — existing remote collect
|
||||
# ---------------------------------------------------------------------------
|
||||
section "inside · collect from koopa"
|
||||
|
||||
if [ "${SKIP_SSH}" = "1" ]; then
|
||||
warn "ssh" "SKIP_SSH=1 — skipped"
|
||||
if [ "${SKIP_SSH}" = "1" ] && [ "${LOCAL_STACK:-0}" != "1" ]; then
|
||||
warn "ssh" "SKIP_SSH=1 and not local — skipped"
|
||||
summary
|
||||
exit 0
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -166,16 +166,34 @@ fi
|
|||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 2) INSIDE — containers can reach deb.taler.net (pasta / install path)
|
||||
# koopa: KOOPA_SSH · stage-lfp: INSIDE_SSH (stagepaysan, low-priv)
|
||||
# ---------------------------------------------------------------------------
|
||||
set_group inside
|
||||
section "versions · inside · containers → deb.taler.net"
|
||||
|
||||
if [ "${SKIP_SSH}" = "1" ]; then
|
||||
warn "ssh" "SKIP_SSH=1 — skip container reachability + installed package compare"
|
||||
_VERS_SSH_HOST=""
|
||||
_VERS_BANK="taler-hacktivism-bank"
|
||||
_VERS_EX="taler-hacktivism-exchange-ansible"
|
||||
_VERS_MER="taler-hacktivism"
|
||||
if [ "${INSIDE_PROFILE:-}" = "stage-lfp" ] \
|
||||
|| [ "${EXPECT_CURRENCY:-}" = "TESTPAYSAN" ] \
|
||||
|| [ -n "${INSIDE_SSH:-}" ]; then
|
||||
_VERS_SSH_HOST="${INSIDE_SSH:-francpaysan-stage-user}"
|
||||
_VERS_BANK="${INSIDE_BANK_CTR:-stage-lfp-bank}"
|
||||
_VERS_EX="${INSIDE_EXCHANGE_CTR:-stage-lfp-exchange-ansible}"
|
||||
_VERS_MER="${INSIDE_MERCHANT_CTR:-stage-lfp-merchant}"
|
||||
elif [ "${LOCAL_STACK:-0}" = "1" ] && [ "${SKIP_SSH:-0}" != "1" ]; then
|
||||
_VERS_SSH_HOST="${KOOPA_SSH}"
|
||||
fi
|
||||
|
||||
if [ -z "$_VERS_SSH_HOST" ]; then
|
||||
info "ssh" "no container SSH for this domain — outside-only package index"
|
||||
info "outside-only" "deb.taler.net public checks completed above"
|
||||
summary
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$_VERS_SSH_HOST" = "${KOOPA_SSH:-}" ] || [ "${INSIDE_PROFILE:-}" = "koopa" ]; then
|
||||
if ! koopa_ssh_ok; then
|
||||
err "ssh" "cannot reach ${KOOPA_SSH} — set SKIP_SSH=1 to skip container checks"
|
||||
info "outside-only" "deb.taler.net public checks completed above"
|
||||
|
|
@ -183,11 +201,21 @@ if ! koopa_ssh_ok; then
|
|||
exit 1
|
||||
fi
|
||||
ok "ssh ${KOOPA_SSH}"
|
||||
else
|
||||
if ! mon_ssh_ok "$_VERS_SSH_HOST"; then
|
||||
err "ssh" "cannot reach ${_VERS_SSH_HOST} (stagepaysan) — skip container package compare"
|
||||
info "outside-only" "deb.taler.net public checks completed above"
|
||||
summary
|
||||
exit 1
|
||||
fi
|
||||
ok "ssh ${_VERS_SSH_HOST}" "stagepaysan container package compare"
|
||||
fi
|
||||
|
||||
INRELEASE_URL="${APT_BASE}/dists/${SUITE}/InRelease"
|
||||
# Write remote script to a file (avoids bash 3.2 parse bugs with case/;; inside $(…)<<heredoc).
|
||||
{
|
||||
printf 'INRELEASE_URL=%q\n' "$INRELEASE_URL"
|
||||
printf 'WANT_BANK=%q; WANT_EX=%q; WANT_MER=%q\n' "$_VERS_BANK" "$_VERS_EX" "$_VERS_MER"
|
||||
cat <<'REMOTE'
|
||||
set +e
|
||||
resolve_ctr() {
|
||||
|
|
@ -196,15 +224,15 @@ resolve_ctr() {
|
|||
if [ -n "$c" ]; then echo "$c"; return; fi
|
||||
case "$want" in
|
||||
*exchange*) podman ps --format '{{.Names}}' 2>/dev/null | grep -i exchange | head -1 ;;
|
||||
*bank*) podman ps --format '{{.Names}}' 2>/dev/null | grep -iE 'hacktivism-bank|taler-bank' | head -1 ;;
|
||||
*bank*) podman ps --format '{{.Names}}' 2>/dev/null | grep -iE 'stage.*bank|hacktivism-bank|taler-bank|lfp-bank' | head -1 ;;
|
||||
*)
|
||||
c=$(podman ps --format '{{.Names}}' 2>/dev/null | grep -E '^taler-hacktivism$' | head -1)
|
||||
c=$(podman ps --format '{{.Names}}' 2>/dev/null | grep -E '^taler-hacktivism$|^stage-lfp-merchant$' | head -1)
|
||||
if [ -n "$c" ]; then echo "$c"; return; fi
|
||||
podman ps --format '{{.Names}}' 2>/dev/null | grep -iE 'merchant|hacktivism' | grep -viE 'bank|exchange' | head -1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
for want in taler-hacktivism-exchange-ansible taler-hacktivism-bank taler-hacktivism; do
|
||||
for want in "$WANT_EX" "$WANT_BANK" "$WANT_MER"; do
|
||||
c=$(resolve_ctr "$want")
|
||||
[ -n "$c" ] || continue
|
||||
role=other
|
||||
|
|
@ -229,7 +257,11 @@ done
|
|||
REMOTE
|
||||
} >"$tmp/remote-versions.sh"
|
||||
|
||||
if [ "$_VERS_SSH_HOST" = "${KOOPA_SSH:-}" ] || [ "${INSIDE_PROFILE:-}" = "koopa" ]; then
|
||||
REMOTE_OUT=$(koopa_ssh_bash 60 <"$tmp/remote-versions.sh" || true)
|
||||
else
|
||||
REMOTE_OUT=$(mon_ssh_bash "$_VERS_SSH_HOST" 60 <"$tmp/remote-versions.sh" || true)
|
||||
fi
|
||||
|
||||
printf '%s\n' "$REMOTE_OUT" | grep -E '^R\|' >"$tmp/reach.tsv" || true
|
||||
printf '%s\n' "$REMOTE_OUT" | grep -E '^S\|' >"$tmp/sources.tsv" || true
|
||||
|
|
|
|||
|
|
@ -211,6 +211,19 @@ apply_taler_domain() {
|
|||
: "${E2E_TEMPLATE_MAP:=5=oeufs-6 4.5=pain-seigle 6=jus-pomme 8.5=fromage-chevre 12=miel-printemps 25=panier-legumes}"
|
||||
: "${E2E_PAY_VALUES:=5 8.5 6}"
|
||||
: "${E2E_WITHDRAW_VALUES:=20 50}"
|
||||
# Inside checks as low-priv stagepaysan (podman, no sudo) — not koopa
|
||||
INSIDE_PROFILE="${INSIDE_PROFILE:-stage-lfp}"
|
||||
INSIDE_SSH="${INSIDE_SSH:-francpaysan-stage-user}"
|
||||
INSIDE_BANK_CTR="${INSIDE_BANK_CTR:-stage-lfp-bank}"
|
||||
INSIDE_EXCHANGE_CTR="${INSIDE_EXCHANGE_CTR:-stage-lfp-exchange-ansible}"
|
||||
INSIDE_MERCHANT_CTR="${INSIDE_MERCHANT_CTR:-stage-lfp-merchant}"
|
||||
# Host pasta ports (127.0.0.1 on francpaysan-host)
|
||||
INSIDE_BANK_PORT="${INSIDE_BANK_PORT:-9032}"
|
||||
INSIDE_EXCHANGE_PORT="${INSIDE_EXCHANGE_PORT:-9031}"
|
||||
INSIDE_MERCHANT_PORT="${INSIDE_MERCHANT_PORT:-9030}"
|
||||
INSIDE_DNS_BANK="${INSIDE_DNS_BANK:-stage.bank.lefrancpaysan.ch}"
|
||||
INSIDE_DNS_EXCHANGE="${INSIDE_DNS_EXCHANGE:-stage.exchange.lefrancpaysan.ch}"
|
||||
INSIDE_DNS_MERCHANT="${INSIDE_DNS_MERCHANT:-stage.monnaie.lefrancpaysan.ch}"
|
||||
;;
|
||||
CHF)
|
||||
WITHDRAW_AMT="${WITHDRAW_AMT:-CHF:20}"
|
||||
|
|
@ -246,10 +259,14 @@ apply_taler_domain() {
|
|||
EXCHANGE_PUBLIC=${EXCHANGE_PUBLIC%/}
|
||||
MERCHANT_PUBLIC=${MERCHANT_PUBLIC%/}
|
||||
|
||||
# Hard rule: only the local koopa/hacktivism stack may use SSH
|
||||
# Koopa SSH only for LOCAL_STACK=1. Stage LFP uses INSIDE_SSH (stagepaysan) separately.
|
||||
if [ "${LOCAL_STACK}" != "1" ]; then
|
||||
SKIP_SSH=1
|
||||
fi
|
||||
# Default inside profile for local GOA
|
||||
if [ "${LOCAL_STACK}" = "1" ]; then
|
||||
INSIDE_PROFILE="${INSIDE_PROFILE:-koopa}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Apply TALER_DOMAIN from env once (CLI exports TALER_DOMAIN_APPLIED=1 after overrides).
|
||||
|
|
@ -310,6 +327,20 @@ with_timeout() {
|
|||
' "$secs" "$@"
|
||||
}
|
||||
|
||||
# Generic short SSH to a named host (low-priv stagepaysan or koopa).
|
||||
# usage: mon_ssh_bash HOST [timeout] <<'EOF' ... EOF
|
||||
mon_ssh_bash() {
|
||||
local host="$1" t="${2:-$SSH_CMD_TIMEOUT}"
|
||||
[ -n "$host" ] || return 1
|
||||
with_timeout "$t" ssh "${SSH_BASE_OPTS[@]}" "$host" bash -s
|
||||
}
|
||||
mon_ssh_ok() {
|
||||
local host="$1"
|
||||
[ -n "$host" ] || return 1
|
||||
with_timeout $((SSH_CONNECT_TIMEOUT + 5)) \
|
||||
ssh "${SSH_BASE_OPTS[@]}" "$host" true >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Pick a working SSH host: KOOPA_SSH first, then KOOPA_SSH_FALLBACKS (koopa-external).
|
||||
# Sets KOOPA_SSH to the first host that answers. 0 = ok, 1 = none.
|
||||
KOOPA_SSH_RESOLVED=0
|
||||
|
|
|
|||
|
|
@ -489,9 +489,9 @@ print(rep["summary"])
|
|||
PY
|
||||
}
|
||||
|
||||
# --- Taler stack load on koopa (host + bank/exchange/merchant) ---
|
||||
# --- Taler stack load (host + bank/exchange/merchant) ---
|
||||
# Writes JSON to $1. RAM, process counts, DB sizes, disk I/O counters.
|
||||
# Uses KOOPA_SSH with fallback to KOOPA_SSH_FALLBACKS (koopa-external).
|
||||
# koopa: KOOPA_SSH (+ fallbacks). stage-lfp: INSIDE_SSH (stagepaysan) + stage-lfp-* names.
|
||||
metrics_taler_load() {
|
||||
local out="${1:-$METRICS_DIR/load.json}"
|
||||
local label="${2:-snap}"
|
||||
|
|
@ -502,7 +502,20 @@ metrics_taler_load() {
|
|||
fi
|
||||
local raw=""
|
||||
local remote_py
|
||||
remote_py=$(cat <<'PY'
|
||||
local _m_bank _m_mer _m_ex _m_ssh
|
||||
_m_bank="taler-hacktivism-bank"
|
||||
_m_mer="taler-hacktivism"
|
||||
_m_ex="taler-hacktivism-exchange-ansible"
|
||||
_m_ssh=""
|
||||
if [ "${INSIDE_PROFILE:-}" = "stage-lfp" ] \
|
||||
|| [ "${EXPECT_CURRENCY:-}" = "TESTPAYSAN" ] \
|
||||
|| { [ -n "${INSIDE_SSH:-}" ] && [ "${LOCAL_STACK:-0}" != "1" ]; }; then
|
||||
_m_bank="${INSIDE_BANK_CTR:-stage-lfp-bank}"
|
||||
_m_mer="${INSIDE_MERCHANT_CTR:-stage-lfp-merchant}"
|
||||
_m_ex="${INSIDE_EXCHANGE_CTR:-stage-lfp-exchange-ansible}"
|
||||
_m_ssh="${INSIDE_SSH:-francpaysan-stage-user}"
|
||||
fi
|
||||
remote_py=$(cat <<PY
|
||||
import base64, json, os, re, subprocess, time
|
||||
from collections import defaultdict
|
||||
|
||||
|
|
@ -557,8 +570,12 @@ def disk_io():
|
|||
return {"sectors_read": r, "sectors_written": w,
|
||||
"approx_write_bytes": w*512, "approx_read_bytes": r*512}
|
||||
|
||||
CTRS = [("bank","taler-hacktivism-bank"),("merchant","taler-hacktivism"),
|
||||
("exchange","taler-hacktivism-exchange-ansible")]
|
||||
CTRS = [("bank","${_m_bank}"),("merchant","${_m_mer}"),
|
||||
("exchange","${_m_ex}")]
|
||||
PY
|
||||
)
|
||||
# Append the rest of the remote probe (quoted so shell does not expand)
|
||||
remote_py+=$(cat <<'PY'
|
||||
|
||||
def running(name):
|
||||
return sh(f"podman inspect -f '{{{{.State.Running}}}}' {name}").strip() == "true"
|
||||
|
|
@ -715,19 +732,25 @@ print(json.dumps({
|
|||
}))
|
||||
PY
|
||||
)
|
||||
# Prefer SSH to koopa (LAN or koopa-external). Local podman only if we are on the host.
|
||||
if [ "${SKIP_SSH:-0}" != "1" ] && type koopa_ssh_ok >/dev/null 2>&1 && koopa_ssh_ok; then
|
||||
# Prefer stagepaysan (stage-lfp), else koopa SSH, else local podman only on LOCAL_STACK.
|
||||
if [ -n "${_m_ssh}" ] && type mon_ssh_ok >/dev/null 2>&1 && mon_ssh_ok "${_m_ssh}"; then
|
||||
raw=$(printf '%s' "$remote_py" | with_timeout "${METRICS_LOAD_SSH_TIMEOUT:-90}" \
|
||||
ssh "${SSH_BASE_OPTS[@]}" "${_m_ssh}" python3 - 2>/dev/null || true)
|
||||
elif [ "${SKIP_SSH:-0}" != "1" ] && type koopa_ssh_ok >/dev/null 2>&1 && koopa_ssh_ok; then
|
||||
if type koopa_ssh_python >/dev/null 2>&1; then
|
||||
raw=$(printf '%s' "$remote_py" | koopa_ssh_python "${METRICS_LOAD_SSH_TIMEOUT:-90}" 2>/dev/null || true)
|
||||
else
|
||||
raw=$(printf '%s' "$remote_py" | with_timeout "${METRICS_LOAD_SSH_TIMEOUT:-90}" \
|
||||
ssh "${SSH_BASE_OPTS[@]}" "${KOOPA_SSH}" python3 - 2>/dev/null || true)
|
||||
fi
|
||||
elif command -v podman >/dev/null 2>&1; then
|
||||
raw=$(python3 -c "$remote_py" 2>/dev/null || true)
|
||||
elif [ "${LOCAL_STACK:-0}" = "1" ] && command -v podman >/dev/null 2>&1; then
|
||||
raw=$(printf '%s' "$remote_py" | python3 - 2>/dev/null || true)
|
||||
else
|
||||
printf '%s\n' "{\"ok\":false,\"reason\":\"no-ssh-for-load\",\"label\":\"$label\"}" >"$out"
|
||||
return 0
|
||||
fi
|
||||
if [ -z "$raw" ]; then
|
||||
printf '%s\n' "{\"ok\":false,\"reason\":\"probe-failed\",\"label\":\"$label\",\"ssh\":\"${KOOPA_SSH:-?}\"}" >"$out"
|
||||
printf '%s\n' "{\"ok\":false,\"reason\":\"probe-failed\",\"label\":\"$label\",\"ssh\":\"${_m_ssh:-${KOOPA_SSH:-?}}\"}" >"$out"
|
||||
return 1
|
||||
fi
|
||||
printf '%s\n' "$raw" | python3 -c '
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@
|
|||
# MERCHANT_INSTANCE_PASSWORD=
|
||||
|
||||
# --- FrancPaysan STAGE (TESTPAYSAN) e2e ---
|
||||
# Default phases for -d stage.lefrancpaysan.ch: urls + e2e
|
||||
# Default phases for -d stage.lefrancpaysan.ch: urls + inside + versions + e2e
|
||||
# inside uses francpaysan-stage-user (stagepaysan); stats from public HTTPS.
|
||||
# Admin credit (required for ATM withdraw ladder on stage):
|
||||
# E2E_BANK_ADMIN_PASS=… # or auto-load via SSH francpaysan-host
|
||||
# FRANCPAYSAN_SSH=francpaysan-host
|
||||
|
|
|
|||
|
|
@ -154,6 +154,10 @@ export WITHDRAW_AMT PAY_AMT CREDIT_AMT MERCHANT_INSTANCE
|
|||
export E2E_FAKE_INCOMING E2E_REMOTE E2E_VARIABLE E2E_ATM_MAX
|
||||
export E2E_WITHDRAW_VALUES E2E_PAY_VALUES E2E_USE_TEMPLATES E2E_TEMPLATE_MAP
|
||||
export PAIVANA_PUBLIC E2E_PAIVANA E2E_PAIVANA_TEMPLATE E2E_PAIVANA_AMOUNT E2E_PAIVANA_INSTANCE
|
||||
export INSIDE_PROFILE INSIDE_SSH
|
||||
export INSIDE_BANK_CTR INSIDE_EXCHANGE_CTR INSIDE_MERCHANT_CTR
|
||||
export INSIDE_BANK_PORT INSIDE_EXCHANGE_PORT INSIDE_MERCHANT_PORT
|
||||
export INSIDE_DNS_BANK INSIDE_DNS_EXCHANGE INSIDE_DNS_MERCHANT
|
||||
# Ladder: withdraw then pay — 0 + random mids + max-1 + max (see check_goa_ladder.sh).
|
||||
# Defaults so set -u export is safe when vars were never set by caller.
|
||||
: "${LADDER_STEPS:=23}"
|
||||
|
|
@ -181,17 +185,17 @@ export LADDER_PAY LADDER_WITHDRAW_SCALE LADDER_PAY_SETTLE_ROUNDS
|
|||
export TALER_DOMAIN_APPLIED=1
|
||||
|
||||
# Default phases
|
||||
# - local GOA (koopa): urls + SSH phases + e2e
|
||||
# - FrancPaysan STAGE (TESTPAYSAN / stage.*lefrancpaysan*): urls + e2e
|
||||
# (public withdraw + template pay — no SSH)
|
||||
# - other remote: urls only (pass "e2e" explicitly)
|
||||
# - local GOA (koopa): urls + inside + versions + e2e
|
||||
# - FrancPaysan STAGE: urls + inside (stagepaysan) + versions + e2e
|
||||
# - other remote: urls only (pass e2e/inside explicitly)
|
||||
if [ "${#PHASES[@]}" -eq 0 ]; then
|
||||
if [ "${LOCAL_STACK}" = "1" ]; then
|
||||
PHASES=(urls inside versions e2e)
|
||||
elif [ "${EXPECT_CURRENCY:-}" = "TESTPAYSAN" ] \
|
||||
|| [[ "${TALER_DOMAIN:-}" == stage.*lefrancpaysan* ]] \
|
||||
|| [[ "${TALER_DOMAIN:-}" == *stage.lefrancpaysan* ]]; then
|
||||
PHASES=(urls e2e)
|
||||
# Like hacktivism breadth: public urls + inside (stagepaysan) + versions + e2e
|
||||
PHASES=(urls inside versions e2e)
|
||||
else
|
||||
PHASES=(urls)
|
||||
fi
|
||||
|
|
@ -202,8 +206,10 @@ for p in "${PHASES[@]}"; do
|
|||
if [ "$p" = "all" ]; then
|
||||
if [ "${LOCAL_STACK}" = "1" ]; then
|
||||
OUT_PHASES+=(urls inside versions sanity e2e)
|
||||
elif [ -n "${INSIDE_SSH:-}" ] || [ "${INSIDE_PROFILE:-}" = "stage-lfp" ]; then
|
||||
OUT_PHASES+=(urls inside versions e2e)
|
||||
else
|
||||
# remote: repo index check only (no installed pkgs without SSH)
|
||||
# remote without inside SSH: public + optional e2e
|
||||
OUT_PHASES+=(urls versions e2e)
|
||||
fi
|
||||
else
|
||||
|
|
@ -213,15 +219,21 @@ done
|
|||
PHASES=()
|
||||
seen=" "
|
||||
for p in "${OUT_PHASES[@]}"; do
|
||||
# Drop SSH-only phases for non-koopa (e2e is allowed — public path only)
|
||||
# versions still runs: outside-in deb.taler.net checks; container parts soft-skip if no SSH
|
||||
if [ "${LOCAL_STACK}" != "1" ] || [ "${SKIP_SSH}" = "1" ]; then
|
||||
case "$p" in inside|server)
|
||||
echo "[INFO] skip phase '$p' (only koopa uses SSH)" >&2
|
||||
# server = koopa-only. inside allowed on koopa OR stagepaysan (INSIDE_SSH).
|
||||
case "$p" in
|
||||
server)
|
||||
if [ "${LOCAL_STACK}" != "1" ]; then
|
||||
echo "[INFO] skip phase 'server' (koopa only)" >&2
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
inside)
|
||||
if [ "${LOCAL_STACK}" != "1" ] && [ -z "${INSIDE_SSH:-}" ] && [ "${INSIDE_PROFILE:-}" != "stage-lfp" ]; then
|
||||
echo "[INFO] skip phase 'inside' (no INSIDE_SSH / not local)" >&2
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
case "$seen" in *" $p "*) ;; *) PHASES+=("$p"); seen="$seen$p " ;; esac
|
||||
done
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue