scripts: sanity/dns/wallet-cli helpers; ops cleanup
This commit is contained in:
parent
1181680a4b
commit
be05666737
18 changed files with 1440 additions and 0 deletions
31
scripts/taler-sanity/README.md
Normal file
31
scripts/taler-sanity/README.md
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# Taler sanity checks (koopa)
|
||||
|
||||
Run **on koopa as root** (reads `/root/*-password.txt`, may use `podman` as `hernani`).
|
||||
|
||||
| Script | What it checks |
|
||||
|--------|----------------|
|
||||
| `check_helpers-running.sh` | **No systemd:** starts missing exchange/merchant helpers (`ensure_*`), then requires transfer/aggregator/wirewatch/… |
|
||||
| `check_stack-health.sh` | Public + local `/config` and exchange `/keys` HTTP 200; merchant has CHF+GOA |
|
||||
| `check_merchant-delays.sh` | Global + instance delays are short (pay/refund/wire ≤ 120s) |
|
||||
| `check_exchange-wirewatch.sh` | Wire gateway reachable with **bearer**; auth method; hosts pin |
|
||||
| `check_settlement.sh` | Paid orders: `wired`, deposit_total, bank balances/transfers |
|
||||
| `run_all.sh` | Runs all of the above |
|
||||
|
||||
Helper ensure scripts (in containers, no systemd):
|
||||
|
||||
| Script | Role |
|
||||
|--------|------|
|
||||
| `../taler-exchange/ensure_exchange_helpers.sh` | `nohup` aggregator, closer, wirewatch, **transfer** |
|
||||
| `../taler-merchant/ensure_merchant_helpers.sh` | `nohup` wirewatch, depositcheck, kyccheck, webhook, … |
|
||||
| Health: `check_*-health.sh` | Calls ensure (unless `SKIP_ENSURE=1`), then **FAIL** if still missing |
|
||||
|
||||
```bash
|
||||
# on koopa
|
||||
cd /path/to/koopa-admin-log/scripts/taler-sanity
|
||||
./run_all.sh
|
||||
./check_settlement.sh 2026.190-03V36SPAZ8CK6
|
||||
```
|
||||
|
||||
Env overrides: `BANK_URL`, `MERCHANT_URL`, `EXCHANGE_PUBLIC`, `BANK_PUBLIC`, `MERCHANT_PUBLIC`, `MERCHANT_INSTANCE`.
|
||||
|
||||
See also: `../taler-wallet-cli/` for end-to-end withdraw → pay → settlement.
|
||||
92
scripts/taler-sanity/check_exchange-wirewatch.sh
Normal file
92
scripts/taler-sanity/check_exchange-wirewatch.sh
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
#!/bin/bash
|
||||
# Sanity: exchange can read bank wire gateway (bearer + public URL).
|
||||
# Run on koopa as root (needs /root/bank-exchange-password.txt + podman).
|
||||
set -euo pipefail
|
||||
ROOT=$(cd "$(dirname "$0")" && pwd)
|
||||
# shellcheck source=lib.sh
|
||||
source "$ROOT/lib.sh"
|
||||
need_root
|
||||
|
||||
echo "=== Exchange wirewatch / wire gateway ==="
|
||||
|
||||
if ! read_pw EPW /root/bank-exchange-password.txt; then
|
||||
fail "missing /root/bank-exchange-password.txt"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ET=$(bank_token exchange "$EPW")
|
||||
if [ -z "$ET" ]; then
|
||||
fail "could not get bank token for exchange user"
|
||||
exit 1
|
||||
fi
|
||||
pass "bank token for exchange user"
|
||||
|
||||
# History must work with Bearer (Basic is rejected by libeufin on history)
|
||||
tmp=$(mktemp)
|
||||
code=$(curl -sk -m 15 -o "$tmp" -w '%{http_code}' \
|
||||
-H "Authorization: Bearer ${ET}" \
|
||||
"${BANK_PUBLIC}/accounts/exchange/taler-wire-gateway/history/incoming?delta=-10")
|
||||
if [ "$code" = "200" ]; then
|
||||
pass "wire gateway history via ${BANK_PUBLIC} (HTTP $code)"
|
||||
python3 -c 'import json,sys; d=json.load(open(sys.argv[1])); print(" incoming_count", len(d.get("incoming_transactions") or []))' "$tmp"
|
||||
else
|
||||
# fallback local
|
||||
code2=$(curl -sS -m 15 -o "$tmp" -w '%{http_code}' \
|
||||
-H "Authorization: Bearer ${ET}" \
|
||||
"${BANK_URL}/accounts/exchange/taler-wire-gateway/history/incoming?delta=-10")
|
||||
if [ "$code2" = "200" ]; then
|
||||
warn "public wire gateway HTTP $code; local BANK_URL OK ($code2) — check DNS/hosts in exchange container"
|
||||
else
|
||||
fail "wire gateway history public=$code local=$code2"
|
||||
fi
|
||||
fi
|
||||
rm -f "$tmp"
|
||||
|
||||
# Basic must fail on history (documents expected auth mode)
|
||||
code_b=$(curl -sk -m 10 -o /dev/null -w '%{http_code}' \
|
||||
-u "exchange:${EPW}" \
|
||||
"${BANK_URL}/accounts/exchange/taler-wire-gateway/history/incoming?delta=-5")
|
||||
if [ "$code_b" = "401" ]; then
|
||||
pass "Basic auth correctly rejected on history ($code_b) — use bearer TOKEN"
|
||||
else
|
||||
warn "Basic on history returned $code_b (expected 401)"
|
||||
fi
|
||||
|
||||
# Container credential + wirewatch process
|
||||
if su - hernani -c 'podman exec taler-exchange-hacktivism true' 2>/dev/null; then
|
||||
su - hernani -c 'podman exec taler-exchange-hacktivism bash -c "
|
||||
set +e
|
||||
echo \"--- secret (redacted) ---\"
|
||||
if [ -r /etc/taler-exchange/secrets/exchange-accountcredentials-1.secret.conf ]; then
|
||||
sed \"s/secret-token:.*/secret-token:***/; s/^TOKEN = .*/TOKEN = ***/; s/^PASSWORD = .*/PASSWORD = ***/\" \
|
||||
/etc/taler-exchange/secrets/exchange-accountcredentials-1.secret.conf
|
||||
else
|
||||
# root-only file: cat as root via outer exec
|
||||
true
|
||||
fi
|
||||
echo \"--- hosts bank ---\"
|
||||
grep bank.hacktivism.ch /etc/hosts || echo \"(no hosts pin)\"
|
||||
echo \"--- wirewatch ---\"
|
||||
ps -eo pid,stat,args | grep \"[w]irewatch\" || echo \"(no wirewatch process)\"
|
||||
"' 2>&1 || warn "podman exec exchange failed"
|
||||
|
||||
AUTH_METHOD=$(su - hernani -c 'podman exec -u root taler-exchange-hacktivism \
|
||||
grep -E "^WIRE_GATEWAY_AUTH_METHOD" /etc/taler-exchange/secrets/exchange-accountcredentials-1.secret.conf' 2>/dev/null | awk '{print $3}')
|
||||
GW_URL=$(su - hernani -c 'podman exec -u root taler-exchange-hacktivism \
|
||||
grep -E "^WIRE_GATEWAY_URL" /etc/taler-exchange/secrets/exchange-accountcredentials-1.secret.conf' 2>/dev/null | awk '{print $3}')
|
||||
info "WIRE_GATEWAY_URL=$GW_URL"
|
||||
info "WIRE_GATEWAY_AUTH_METHOD=$AUTH_METHOD"
|
||||
if [ "$AUTH_METHOD" = "bearer" ]; then pass "auth method bearer"
|
||||
else fail "auth method is '$AUTH_METHOD' (want bearer + TOKEN=)"
|
||||
fi
|
||||
case "$GW_URL" in
|
||||
https://bank.hacktivism.ch/*) pass "gateway uses public bank URL" ;;
|
||||
http://127.*|http://host.containers*) warn "gateway uses local URL: $GW_URL" ;;
|
||||
*) warn "unexpected gateway URL: $GW_URL" ;;
|
||||
esac
|
||||
else
|
||||
warn "exchange container not reachable via podman"
|
||||
fi
|
||||
|
||||
echo "=== summary fails=$FAILS ==="
|
||||
exit "$FAILS"
|
||||
81
scripts/taler-sanity/check_helpers-running.sh
Executable file
81
scripts/taler-sanity/check_helpers-running.sh
Executable file
|
|
@ -0,0 +1,81 @@
|
|||
#!/bin/bash
|
||||
# Sanity: ensure exchange + merchant helpers are up (no systemd).
|
||||
# Runs on koopa as root; uses podman into both containers.
|
||||
set -euo pipefail
|
||||
ROOT=$(cd "$(dirname "$0")" && pwd)
|
||||
# shellcheck source=lib.sh
|
||||
source "$ROOT/lib.sh"
|
||||
need_root
|
||||
|
||||
fail=0
|
||||
pass() { echo "OK $1"; }
|
||||
warn() { echo "WARN $1"; }
|
||||
bad() { echo "FAIL $1"; fail=$((fail + 1)); }
|
||||
|
||||
EXC_CT="${EXCHANGE_CONTAINER:-taler-exchange-hacktivism}"
|
||||
MER_CT="${MERCHANT_CONTAINER:-taler-hacktivism}"
|
||||
|
||||
echo "=== ensure + check helpers (no systemd) ==="
|
||||
|
||||
# Deploy/ensure scripts if present on host under admin-log mount or /tmp
|
||||
deploy_into() {
|
||||
local ct="$1"
|
||||
local src="$2"
|
||||
local dst="$3"
|
||||
if [ -f "$src" ]; then
|
||||
su - hernani -c "podman cp $(printf %q "$src") ${ct}:${dst}" 2>/dev/null \
|
||||
|| podman cp "$src" "${ct}:${dst}" 2>/dev/null || true
|
||||
su - hernani -c "podman exec ${ct} chmod 755 ${dst}" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
ADMIN="${KOOPA_ADMIN_LOG:-/home/hernani/koopa-admin-log}"
|
||||
# Prefer workspace copy if synced; else scripts next to this file
|
||||
EX_SCRIPTS="$ROOT/../taler-exchange"
|
||||
MER_SCRIPTS="$ROOT/../taler-merchant"
|
||||
[ -d "$ADMIN/scripts/taler-exchange" ] && EX_SCRIPTS="$ADMIN/scripts/taler-exchange"
|
||||
[ -d "$ADMIN/scripts/taler-merchant" ] && MER_SCRIPTS="$ADMIN/scripts/taler-merchant"
|
||||
|
||||
deploy_into "$EXC_CT" "$EX_SCRIPTS/ensure_exchange_helpers.sh" /usr/local/bin/ensure_exchange_helpers.sh
|
||||
deploy_into "$EXC_CT" "$EX_SCRIPTS/check_exchange-health.sh" /usr/local/bin/check_exchange-health.sh
|
||||
deploy_into "$MER_CT" "$MER_SCRIPTS/ensure_merchant_helpers.sh" /usr/local/bin/ensure_merchant_helpers.sh
|
||||
deploy_into "$MER_CT" "$MER_SCRIPTS/check_merchant-health.sh" /usr/local/bin/check_merchant-health.sh
|
||||
|
||||
echo "--- exchange container: ensure ---"
|
||||
if su - hernani -c "podman exec $EXC_CT /usr/local/bin/ensure_exchange_helpers.sh"; then
|
||||
pass "exchange helpers ensure"
|
||||
else
|
||||
bad "exchange helpers ensure failed"
|
||||
fi
|
||||
|
||||
echo "--- merchant container: ensure ---"
|
||||
if su - hernani -c "podman exec $MER_CT /usr/local/bin/ensure_merchant_helpers.sh"; then
|
||||
pass "merchant helpers ensure"
|
||||
else
|
||||
bad "merchant helpers ensure failed"
|
||||
fi
|
||||
|
||||
echo "--- process presence ---"
|
||||
check_ct_proc() {
|
||||
local ct="$1"
|
||||
local p="$2"
|
||||
# COMM is 15 chars — match full cmdline
|
||||
if su - hernani -c "podman exec $ct pgrep -f '(^|/)${p}( |$)'" >/dev/null 2>&1; then
|
||||
pass "$ct: $p"
|
||||
else
|
||||
bad "$ct: $p missing"
|
||||
fi
|
||||
}
|
||||
|
||||
for p in taler-exchange-httpd taler-exchange-aggregator taler-exchange-transfer \
|
||||
taler-exchange-wirewatch taler-exchange-closer; do
|
||||
check_ct_proc "$EXC_CT" "$p"
|
||||
done
|
||||
for p in taler-merchant-httpd taler-merchant-wirewatch taler-merchant-depositcheck \
|
||||
taler-merchant-webhook taler-merchant-kyccheck \
|
||||
taler-merchant-exchangekeyupdate taler-merchant-reconciliation; do
|
||||
check_ct_proc "$MER_CT" "$p"
|
||||
done
|
||||
|
||||
echo "=== summary fails=$fail ==="
|
||||
exit "$fail"
|
||||
72
scripts/taler-sanity/check_merchant-delays.sh
Normal file
72
scripts/taler-sanity/check_merchant-delays.sh
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
#!/bin/bash
|
||||
# Sanity: merchant global + demo instance delays are demo-short (pay/refund/wire).
|
||||
# Run on koopa (network to :9010 / public merchant).
|
||||
set -euo pipefail
|
||||
ROOT=$(cd "$(dirname "$0")" && pwd)
|
||||
# shellcheck source=lib.sh
|
||||
source "$ROOT/lib.sh"
|
||||
|
||||
# Expected upper bounds (seconds) — fail if longer (package defaults 1d/15d/1w)
|
||||
MAX_PAY_S=${MAX_PAY_S:-120}
|
||||
MAX_REFUND_S=${MAX_REFUND_S:-120}
|
||||
MAX_WIRE_S=${MAX_WIRE_S:-120}
|
||||
|
||||
echo "=== Merchant delay defaults (expect short demo values) ==="
|
||||
|
||||
tmp=$(mktemp)
|
||||
curl -sk -m 12 -o "$tmp" "${MERCHANT_PUBLIC}/config" || curl -sk -m 12 -o "$tmp" "${MERCHANT_URL}/config"
|
||||
python3 - "$tmp" "$MAX_PAY_S" "$MAX_REFUND_S" "$MAX_WIRE_S" <<'PY'
|
||||
import json,sys
|
||||
d=json.load(open(sys.argv[1]))
|
||||
max_pay, max_ref, max_wire = map(float, sys.argv[2:5])
|
||||
fails=0
|
||||
for key, mx in (
|
||||
("default_pay_delay", max_pay),
|
||||
("default_refund_delay", max_ref),
|
||||
("default_wire_transfer_delay", max_wire),
|
||||
):
|
||||
us=d.get(key,{}).get("d_us")
|
||||
s=(us or 0)/1e6
|
||||
ok = us is not None and s <= mx
|
||||
print(f"{'OK' if ok else 'FAIL'} {key}: {s:.0f}s (max {mx:.0f}s)")
|
||||
if not ok: fails+=1
|
||||
print("currency", d.get("currency"))
|
||||
sys.exit(fails)
|
||||
PY
|
||||
ec=$?
|
||||
rm -f "$tmp"
|
||||
FAILS=$((FAILS + ec))
|
||||
|
||||
# Instance goa-demo if password present
|
||||
if [ -f /root/merchant-goa-demo-cp4zqk-password.txt ]; then
|
||||
MPW=$(tr -d '\n' </root/merchant-goa-demo-cp4zqk-password.txt)
|
||||
tmp=$(mktemp)
|
||||
curl -sk -m 12 -H "Authorization: Bearer secret-token:${MPW}" \
|
||||
-o "$tmp" "${MERCHANT_URL}/instances/goa-demo-cp4zqk/private/" || true
|
||||
if [ -s "$tmp" ]; then
|
||||
python3 - "$tmp" "$MAX_PAY_S" "$MAX_REFUND_S" "$MAX_WIRE_S" <<'PY'
|
||||
import json,sys
|
||||
d=json.load(open(sys.argv[1]))
|
||||
max_pay, max_ref, max_wire = map(float, sys.argv[2:5])
|
||||
fails=0
|
||||
for key, mx in (
|
||||
("default_pay_delay", max_pay),
|
||||
("default_refund_delay", max_ref),
|
||||
("default_wire_transfer_delay", max_wire),
|
||||
):
|
||||
us=d.get(key,{}).get("d_us")
|
||||
s=(us or 0)/1e6
|
||||
ok = us is not None and s <= mx
|
||||
print(f"{'OK' if ok else 'FAIL'} instance {key}: {s:.0f}s")
|
||||
if not ok: fails+=1
|
||||
sys.exit(fails)
|
||||
PY
|
||||
FAILS=$((FAILS + $?))
|
||||
else
|
||||
warn "could not load instance goa-demo-cp4zqk"
|
||||
fi
|
||||
rm -f "$tmp"
|
||||
fi
|
||||
|
||||
echo "=== summary fails=$FAILS ==="
|
||||
exit "$FAILS"
|
||||
119
scripts/taler-sanity/check_settlement.sh
Normal file
119
scripts/taler-sanity/check_settlement.sh
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
#!/bin/bash
|
||||
# Sanity / ops: check paid orders wired? bank transfers? balances?
|
||||
# Run on koopa as root.
|
||||
#
|
||||
# Usage:
|
||||
# check_settlement.sh # all paid orders for goa-demo
|
||||
# check_settlement.sh ORDER_ID # one order
|
||||
# MERCHANT_INSTANCE=foo check_settlement.sh
|
||||
set -euo pipefail
|
||||
ROOT=$(cd "$(dirname "$0")" && pwd)
|
||||
# shellcheck source=lib.sh
|
||||
source "$ROOT/lib.sh"
|
||||
need_root
|
||||
|
||||
INST="${MERCHANT_INSTANCE:-goa-demo-cp4zqk}"
|
||||
ORDER_ID="${1:-}"
|
||||
|
||||
if ! read_pw MPW "/root/merchant-${INST}-password.txt"; then
|
||||
read_pw MPW /root/merchant-goa-demo-cp4zqk-password.txt || true
|
||||
fi
|
||||
if [ -z "${MPW:-}" ]; then
|
||||
fail "no merchant password for $INST"
|
||||
exit 1
|
||||
fi
|
||||
AUTH=$(merchant_auth_header "$MPW")
|
||||
|
||||
echo "=== Settlement check instance=$INST ==="
|
||||
|
||||
tmp=$(mktemp)
|
||||
curl -sk -m 15 -H "$AUTH" -o "$tmp" \
|
||||
"${MERCHANT_URL}/instances/${INST}/private/orders?paid=YES"
|
||||
|
||||
python3 - "$tmp" "$ORDER_ID" <<'PY'
|
||||
import json,sys,time
|
||||
d=json.load(open(sys.argv[1]))
|
||||
want=sys.argv[2] or None
|
||||
orders=d.get("orders") or []
|
||||
if want:
|
||||
orders=[o for o in orders if o.get("order_id")==want]
|
||||
if not orders:
|
||||
print("FAIL no paid orders" + (f" matching {want}" if want else ""))
|
||||
sys.exit(1)
|
||||
print(f"INFO paid_orders={len(orders)}")
|
||||
for o in orders:
|
||||
print(f" - {o.get('order_id')} amount={o.get('amount')} summary={o.get('summary')!r} paid={o.get('paid')}")
|
||||
sys.exit(0)
|
||||
PY
|
||||
ec=$?
|
||||
[ "$ec" -eq 0 ] || FAILS=$((FAILS + 1))
|
||||
|
||||
# Detail each order
|
||||
mapfile -t OIDS < <(python3 -c 'import json,sys; d=json.load(open(sys.argv[1])); want=sys.argv[2] or None
|
||||
oids=[o["order_id"] for o in d.get("orders",[])]
|
||||
print("\n".join([x for x in oids if not want or x==want]))' "$tmp" "$ORDER_ID")
|
||||
|
||||
for oid in "${OIDS[@]}"; do
|
||||
echo "--- order $oid ---"
|
||||
ot=$(mktemp)
|
||||
curl -sk -m 15 -H "$AUTH" -o "$ot" \
|
||||
"${MERCHANT_URL}/instances/${INST}/private/orders/${oid}"
|
||||
python3 - "$ot" <<'PY'
|
||||
import json,sys,time
|
||||
d=json.load(open(sys.argv[1]))
|
||||
ct=d.get("contract_terms") or {}
|
||||
ts=(ct.get("timestamp") or {}).get("t_s")
|
||||
rd=(ct.get("refund_deadline") or {}).get("t_s")
|
||||
wd=(ct.get("wire_transfer_deadline") or {}).get("t_s")
|
||||
now=int(time.time())
|
||||
print(" status", d.get("order_status"), "wired", d.get("wired"), "deposit_total", d.get("deposit_total"))
|
||||
print(" amount", ct.get("amount"), "summary", ct.get("summary"))
|
||||
if ts and rd and wd:
|
||||
print(f" age_s={now-ts} refund_in_s={rd-now} wire_in_s={wd-now}")
|
||||
print(f" windows: refund={rd-ts}s wire_from_pay={wd-ts}s (wire_after_refund={wd-rd}s)")
|
||||
if now >= wd and not d.get("wired"):
|
||||
print(" FAIL wire deadline passed but wired=false")
|
||||
sys.exit(2)
|
||||
if now < wd:
|
||||
print(" INFO still before wire deadline — settlement not due yet")
|
||||
if d.get("wired"):
|
||||
print(" OK wired=true")
|
||||
sys.exit(0)
|
||||
PY
|
||||
ec=$?
|
||||
[ "$ec" -eq 2 ] && FAILS=$((FAILS + 1))
|
||||
rm -f "$ot"
|
||||
done
|
||||
|
||||
echo "=== private/transfers ==="
|
||||
tr=$(mktemp)
|
||||
curl -sk -m 15 -H "$AUTH" -o "$tr" \
|
||||
"${MERCHANT_URL}/instances/${INST}/private/transfers"
|
||||
python3 -c 'import json,sys; d=json.load(open(sys.argv[1])); t=d.get("transfers") or []; print(f" transfers={len(t)}");
|
||||
[print(" ", x) for x in t[:10]]' "$tr"
|
||||
rm -f "$tr" "$tmp"
|
||||
|
||||
# Bank balances
|
||||
BANK_USER="${BANK_USER:-$INST}"
|
||||
if read_pw BPW "/root/bank-${BANK_USER}-password.txt" || read_pw BPW /root/bank-goa-demo-cp4zqk-password.txt; then
|
||||
BT=$(bank_token "$BANK_USER" "$BPW")
|
||||
if [ -n "$BT" ]; then
|
||||
curl -sS -m 12 -H "Authorization: Bearer ${BT}" \
|
||||
"${BANK_URL}/accounts/${BANK_USER}" | python3 -c 'import sys,json; d=json.load(sys.stdin); print("merchant_bank_balance", d.get("balance"))'
|
||||
curl -sS -m 12 -H "Authorization: Bearer ${BT}" \
|
||||
"${BANK_URL}/accounts/${BANK_USER}/transactions?delta=-10" \
|
||||
| python3 -c 'import sys,json; d=json.load(sys.stdin); txs=d.get("transactions") or []; print(f"merchant_bank_tx={len(txs)}");
|
||||
[print(f" {t.get(\"direction\")} {t.get(\"amount\")} {t.get(\"subject\",\"\")[:60]}") for t in txs[:8]]'
|
||||
fi
|
||||
fi
|
||||
|
||||
if read_pw EPW /root/bank-exchange-password.txt; then
|
||||
ET=$(bank_token exchange "$EPW")
|
||||
if [ -n "$ET" ]; then
|
||||
curl -sS -m 12 -H "Authorization: Bearer ${ET}" \
|
||||
"${BANK_URL}/accounts/exchange" | python3 -c 'import sys,json; d=json.load(sys.stdin); print("exchange_bank_balance", d.get("balance"))'
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "=== summary fails=$FAILS ==="
|
||||
exit "$FAILS"
|
||||
73
scripts/taler-sanity/check_stack-health.sh
Normal file
73
scripts/taler-sanity/check_stack-health.sh
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
#!/bin/bash
|
||||
# Sanity: public + local Taler endpoints respond (GOA stack).
|
||||
# Run on koopa as root (or any user with network to services).
|
||||
set -euo pipefail
|
||||
ROOT=$(cd "$(dirname "$0")" && pwd)
|
||||
# shellcheck source=lib.sh
|
||||
source "$ROOT/lib.sh"
|
||||
|
||||
echo "=== Taler stack health ==="
|
||||
|
||||
# Public HTTPS (via Caddy / VeciGate)
|
||||
for url in \
|
||||
"${EXCHANGE_PUBLIC}/config" \
|
||||
"${EXCHANGE_PUBLIC}/keys" \
|
||||
"${BANK_PUBLIC}/config" \
|
||||
"${MERCHANT_PUBLIC}/config"
|
||||
do
|
||||
code=$(http_code "$url")
|
||||
if [ "$code" = "200" ]; then pass "$url -> $code"
|
||||
else fail "$url -> $code"
|
||||
fi
|
||||
done
|
||||
|
||||
# Local loopback ports (containers via pasta)
|
||||
for spec in \
|
||||
"bank ${BANK_URL}/config" \
|
||||
"merchant ${MERCHANT_URL}/config" \
|
||||
"exchange-via-public ${EXCHANGE_PUBLIC}/config"
|
||||
do
|
||||
name=${spec%% *}
|
||||
url=${spec#* }
|
||||
code=$(http_code "$url")
|
||||
if [ "$code" = "200" ]; then pass "local $name -> $code"
|
||||
else fail "local $name -> $code"
|
||||
fi
|
||||
done
|
||||
|
||||
# Merchant multi-currency
|
||||
tmp=$(mktemp)
|
||||
curl -sk -m 12 -o "$tmp" "${MERCHANT_PUBLIC}/config" || true
|
||||
if python3 - "$tmp" <<'PY'
|
||||
import json,sys
|
||||
d=json.load(open(sys.argv[1]))
|
||||
ex=[e.get("currency") for e in d.get("exchanges") or []]
|
||||
cur=list((d.get("currencies") or {}).keys())
|
||||
ok = "GOA" in ex and "CHF" in ex and "GOA" in cur
|
||||
print("currency_default", d.get("currency"))
|
||||
print("exchanges", ex)
|
||||
print("currencies", cur)
|
||||
sys.exit(0 if ok else 1)
|
||||
PY
|
||||
then pass "merchant has CHF + GOA exchanges"
|
||||
else fail "merchant missing CHF/GOA in /config"
|
||||
fi
|
||||
rm -f "$tmp"
|
||||
|
||||
# Exchange currency GOA
|
||||
tmp=$(mktemp)
|
||||
curl -sk -m 12 -o "$tmp" "${EXCHANGE_PUBLIC}/config" || true
|
||||
if python3 - "$tmp" <<'PY'
|
||||
import json,sys
|
||||
d=json.load(open(sys.argv[1]))
|
||||
c=(d.get("currency") or d.get("currency_specification",{}).get("currency"))
|
||||
print("exchange_currency", c)
|
||||
sys.exit(0 if c=="GOA" else 1)
|
||||
PY
|
||||
then pass "exchange currency GOA"
|
||||
else fail "exchange currency not GOA"
|
||||
fi
|
||||
rm -f "$tmp"
|
||||
|
||||
echo "=== summary fails=$FAILS ==="
|
||||
exit "$FAILS"
|
||||
60
scripts/taler-sanity/lib.sh
Normal file
60
scripts/taler-sanity/lib.sh
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# shellcheck shell=bash
|
||||
# Common helpers for Taler sanity checks (run on koopa host as root).
|
||||
# shellcheck disable=SC2034
|
||||
|
||||
: "${BANK_URL:=http://127.0.0.1:9012}"
|
||||
: "${MERCHANT_URL:=https://127.0.0.1:9010}"
|
||||
: "${EXCHANGE_PUBLIC:=https://exchange.hacktivism.ch}"
|
||||
: "${BANK_PUBLIC:=https://bank.hacktivism.ch}"
|
||||
: "${MERCHANT_PUBLIC:=https://taler.hacktivism.ch}"
|
||||
|
||||
pass() { echo "OK $*"; }
|
||||
fail() { echo "FAIL $*"; FAILS=$((FAILS + 1)); }
|
||||
warn() { echo "WARN $*"; }
|
||||
info() { echo "INFO $*"; }
|
||||
|
||||
FAILS=0
|
||||
|
||||
need_root() {
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "This check expects root on koopa (password files under /root)." >&2
|
||||
exit 2
|
||||
fi
|
||||
}
|
||||
|
||||
read_pw() {
|
||||
# read_pw VAR path
|
||||
local _v="$1" _p="$2"
|
||||
if [ ! -f "$_p" ]; then
|
||||
eval "$_v="
|
||||
return 1
|
||||
fi
|
||||
eval "$_v=\$(tr -d '\\n' <\"$_p\")"
|
||||
}
|
||||
|
||||
bank_token() {
|
||||
# bank_token USER PASS -> prints access_token
|
||||
local user="$1" pass="$2"
|
||||
curl -sS -m 15 -u "${user}:${pass}" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"scope":"readwrite","refreshable":true}' \
|
||||
"${BANK_URL}/accounts/${user}/token" \
|
||||
| python3 -c 'import sys,json; print(json.load(sys.stdin).get("access_token",""))'
|
||||
}
|
||||
|
||||
merchant_auth_header() {
|
||||
# merchant_auth_header PASSWORD
|
||||
printf 'Authorization: Bearer secret-token:%s' "$1"
|
||||
}
|
||||
|
||||
http_code() {
|
||||
# http_code URL [curl args...]
|
||||
local url="$1"
|
||||
shift
|
||||
curl -sk -m 12 -o /dev/null -w '%{http_code}' "$@" "$url" 2>/dev/null || echo "000"
|
||||
}
|
||||
|
||||
json_get() {
|
||||
# json_get FILE python-expr-on-d
|
||||
python3 -c "import json,sys; d=json.load(open(sys.argv[1])); print($2)" "$1"
|
||||
}
|
||||
22
scripts/taler-sanity/run_all.sh
Normal file
22
scripts/taler-sanity/run_all.sh
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#!/bin/bash
|
||||
# Run all sanity checks; exit non-zero if any failed.
|
||||
set -euo pipefail
|
||||
ROOT=$(cd "$(dirname "$0")" && pwd)
|
||||
ec=0
|
||||
for s in \
|
||||
check_helpers-running.sh \
|
||||
check_stack-health.sh \
|
||||
check_merchant-delays.sh \
|
||||
check_exchange-wirewatch.sh \
|
||||
check_settlement.sh
|
||||
do
|
||||
echo ""
|
||||
echo "########## $s ##########"
|
||||
if bash "$ROOT/$s"; then
|
||||
echo "PASS $s"
|
||||
else
|
||||
echo "FAIL $s (exit $?)"
|
||||
ec=1
|
||||
fi
|
||||
done
|
||||
exit $ec
|
||||
Loading…
Add table
Add a link
Reference in a new issue