diff --git a/.gitignore b/.gitignore index 9f39d9e..5516c4f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,3 @@ __pycache__/ *.swp *~ .tmp/ -scripts/taler-monitoring/settings.conf diff --git a/2026/2026-07-16--taler-package-upgrade-goa.md b/2026/2026-07-16--taler-package-upgrade-goa.md deleted file mode 100644 index 91a412f..0000000 --- a/2026/2026-07-16--taler-package-upgrade-goa.md +++ /dev/null @@ -1,145 +0,0 @@ -# 2026-07-16 — GOA container package upgrade (trixie debs) - -## Why - -`taler-monitoring.sh versions` reported packages **behind** `deb.taler.net` **trixie**: - -| Component | Package | Was | Target (trixie index) | -|-----------|---------|-----|------------------------| -| bank | libeufin-bank / common | 1.6.6 | **1.6.7** | -| exchange | taler-exchange* / libtalerexchange | 1.6.6 | **1.6.7~dev2** | -| merchant | taler-merchant-webui | 1.6.9 | **1.6.11** | -| merchant | taler-merchant / libtalermerchant | 1.6.9 | still 1.6.9 (no newer in suite for those) | - -Host is openSUSE Tumbleweed — **irrelevant** for these versions. Debs live **inside** Debian-based podman images. - -## Containers - -| Role | Name | -|------|------| -| bank | `taler-hacktivism-bank` | -| exchange | `taler-hacktivism-exchange-ansible` | -| merchant | `taler-hacktivism` | - -**No systemd as PID 1** in these containers. Do **not** rely on `systemctl restart` after apt (policy-rc.d / no bus). Restart with: - -```bash -# bank -podman exec -u root taler-hacktivism-bank \ - runuser -u libeufin-bank -- /usr/local/bin/start_bank.sh --restart - -# merchant -podman exec -u root taler-hacktivism \ - runuser -u taler-merchant-httpd -- /usr/local/bin/start_merchant.sh --restart - -# exchange: base (root) then start_exchange as httpd user -podman exec -u root taler-hacktivism-exchange-ansible \ - bash -c '/root/start_base_services_for_taler_exchange.sh --no-shell 2>/dev/null; \ - runuser -u taler-exchange-httpd -- /usr/local/bin/start_exchange.sh --restart' -``` - -## Procedure (manual) - -```bash -# as root inside each container (example bank) -export DEBIAN_FRONTEND=noninteractive -apt-get update -qq -apt-get install -y libeufin-bank libeufin-common # bank -# exchange: taler-exchange taler-exchange-database libtalerexchange … -# merchant: taler-merchant-webui (and stack as needed) -``` - -Then restart with `start_*.sh` as above. - -**Scripted (host):** `scripts/taler-shared/upgrade-goa-debs.sh` -Copy to koopa or run from a checkout: `./upgrade-goa-debs.sh` / `bank|exchange|merchant`. - -## Lessons from 2026-07-16 run - -1. **`apt-get install` as root works** (`podman exec -u root`); suite `trixie` (+ merchant may also have `trixie-testing`). -2. **`taler-exchange-dbinit` as root fails** (`role "root" does not exist`) — run as `taler-exchange-httpd` if needed. -3. **Bank after upgrade:** if postgres socket was down, bank dies with pool init error; `pg_ctlcluster 17 main start` then `start_bank.sh --restart`. -4. **Merchant `taler-merchant-dbinit` / merchant-0041.sql** can noise-fail (psql cluster path); after `start_merchant.sh --restart`, health check can still be green — verify `https://127.0.0.1:9010/config` and public `taler.hacktivism.ch`. -5. Exchange **postinst** may warn about missing SPA files under `/usr/share/taler-exchange/{aml,kyc}-spa/`; packages `taler-exchange-aml-webui` / `kyc-webui` pull in SPAs — re-check if AML UI is used. -6. **Images are live-writable** (not immutable rebuild): upgraded debs are in the running container layers until next image rebuild/snapshot. - -## Smoke after upgrade - -```bash -curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1:9012/config -curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1:9011/config -curl -skS -o /dev/null -w "%{http_code}\n" https://127.0.0.1:9010/config -# public -curl -skS -o /dev/null -w "%{http_code}\n" https://bank.hacktivism.ch/config -curl -skS -o /dev/null -w "%{http_code}\n" https://exchange.hacktivism.ch/config -curl -skS -o /dev/null -w "%{http_code}\n" https://taler.hacktivism.ch/config -``` - -Laptop: `./scripts/taler-monitoring/taler-monitoring.sh versions` (or `urls`). - -## Result (this day) - -- bank **1.6.7**, exchange **1.6.7~dev2**, merchant-webui **1.6.11** -- public `/config` **200** for bank / exchange / merchant after restarts -- `taler-monitoring.sh -d hacktivism.ch versions` → **behind=0** (all package rows OK) - -## Specific residual problems (re-checked after upgrade) - -Severity: **P1** = breaks settlement/ops soon · **P2** = noise / tooling · **P3** = hygiene. - -### P1 — none known after restarts - -Settlement path: bank/exchange/merchant `/config` 200; merchant health can pass including wirewatch (see below). - -### P2 — `taler-merchant-dbinit` fails when run by hand - -```text -WARNING Could not run PSQL on file …/global_procedures.sql: psql exit code was 1 -ERROR Failed to initialize tables -``` - -- **Schema is actually current:** `_v.patches` includes **`merchant-0041`** (applied 2026-07-16, by role `postgres` during upgrade noise). -- **Service works:** `check_merchant-health.sh` → ALL CRITICAL CHECKS PASSED when helpers are up. -- **Cause (likely):** service-user `psql` / cluster path (`Error: Invalid data directory for cluster 17 main` when run poorly), not missing migrations. -- **Action:** do not treat hand-run `dbinit` exit≠0 as deploy failure; verify `_v.patches` + `/config`. Optional follow-up: fix `pg_wrapper`/`.postgresqlrc` for `taler-merchant-httpd` so dbinit is clean. - -### P2 — merchant health vs wirewatch (race / detect) - -- `check_merchant-health.sh` uses `pgrep` for `taler-merchant-wirewatch`. -- Wirewatch is supervised by **`taler-merchant-wirewatch-supervise.sh`** (restarts on PG NOTIFY exit). -- During restart windows the helper can be absent for seconds → **false FAIL**. -- When wirewatch + supervise are both live, health reports **OK**. -- **Action:** re-run health after 5s; ensure supervise is started after package upgrades (start_merchant / ensure_helpers). - -### P2 — `check_exchange-health.sh` missing in live exchange container - -```text -exec: "/usr/local/bin/check_exchange-health.sh": no such file or directory -``` - -- Script exists in **admin-log** (`scripts/taler-exchange/check_exchange-health.sh`) but was **not installed** into `taler-hacktivism-exchange-ansible`. -- **Action:** copy into image/live `/usr/local/bin/` on next deploy (same as bank/merchant health scripts). - -### P3 — zombie processes inside bank + merchant containers - -- **bank:** defunct `java`, `python3`, occasional `postgres` / `dpkg-preconfigu`. -- **merchant:** many old `taler-merchant-*` defunct (pre-restart leftovers). -- **Cause:** no proper init/reaper (not systemd PID 1); supervise/start scripts leave zombies. -- **Impact:** mostly cosmetic / PID table clutter unless extreme. -- **Action:** periodic container restart or install a tiny reaper; not urgent. - -### P3 — package skew (informational) - -| Package | Installed | Note | -|---------|-----------|------| -| taler-merchant / libtalermerchant / typst | 1.6.9 | no newer in trixie index at check time | -| taler-merchant-webui | 1.6.11 | intentionally newer SPA | -| exchange aml/kyc webui | 1.6.8~dev3 | pulled with exchange upgrade | - -Monitoring does **not** ERROR on this skew when suite index matches installed. - -### Resolved during upgrade (do not re-open without evidence) - -- Version **behind** bank/exchange/webui — fixed. -- Exchange postinst “missing aml-spa/forms.json” — paths **`/usr/share/taler-exchange/{aml,kyc}-spa`** now present after webui packages. -- Bank down after apt — fixed with postgres socket + `start_bank.sh --restart`. diff --git a/scripts/README.md b/scripts/README.md index d062c73..1a1f35f 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -9,7 +9,6 @@ | `taler-shared/` | host **ensure-taler-apps** (post-container app start + auto-confirm) | | `taler-sanity/` | host root checks (stack, settlement, helpers) | | `taler-monitoring/` | **outside-in** public URL walk (`/config` → keys/terms/integration/webui) | -| `taler-shared/` | shared helpers (`upgrade-goa-debs.sh` = apt upgrade **inside** bank/exchange/merchant containers) | | `taler-landing/` | **hernani user systemd**: central landing `stats.json` (full bank scan + alt units) | | `monitoring/` | host `/home/hernani/scripts` (tor relay stats) | | `nym/` | **koopa-nym** build/up/status (nym.com nym-node) | @@ -62,8 +61,4 @@ Exchange one-shots (root, offline / wire): `runuser -u USER -- bash` (never `-u` with `-s` on util-linux). -### Package upgrades (trixie debs inside containers) - -Containers are **not** systemd. After `apt-get install` of Taler/libeufin packages, restart with `start_*.sh` only — see **`taler-shared/upgrade-goa-debs.sh`** and day note `2026/2026-07-16--taler-package-upgrade-goa.md`. Host `zypper` does not update these. - SMS helper symlinks into `/var/taler-src/...` are not copied (merchant only). diff --git a/scripts/taler-monitoring/README.md b/scripts/taler-monitoring/README.md index 3f75b91..6b6df2b 100644 --- a/scripts/taler-monitoring/README.md +++ b/scripts/taler-monitoring/README.md @@ -33,68 +33,16 @@ End of each phase: totals + list of **BLOCKERS** and **ERRORS**. # Other domains — public HTTPS only, never SSH ./taler-monitoring.sh -d taler.net ./taler-monitoring.sh --domain taler-ops.ch -./taler-monitoring.sh -d my.taler-ops.ch urls ./taler-monitoring.sh -d demo.taler.net urls ./taler-monitoring.sh taler.net # bare domain = same as -d - -# Explicit endpoints (any mix; override profile or skip -d) -./taler-monitoring.sh --bank https://bank.demo.taler.net \ - --exchange https://exchange.demo.taler.net \ - --merchant https://backend.demo.taler.net --currency KUDOS urls ``` -## Domain profiles (`domains.conf`) - -Each monitored stack must say **what is bank, exchange, and merchant-backend**. - -Edit **[domains.conf](./domains.conf)** (or set `TALER_DOMAINS_CONF=`): - -```text -# name bank exchange merchant-backend currency local [canonical] -taler-ops.ch bank.taler-ops.ch exchange.taler-ops.ch my.taler-ops.ch CHF 0 -``` - -| Field | Meaning | -|-------|---------| -| **name** | `-d NAME` / `TALER_DOMAIN` match (add alias lines as needed) | -| **bank** | libeufin/bank public host or `https://…` | -| **exchange** | exchange public host or URL | -| **merchant** | merchant **backend** (SPA/API), e.g. `my.taler-ops.ch` | -| **currency** | `GOA` / `KUDOS` / `CHF` / … | -| **local** | `1` = koopa SSH stack; `0` = public only | -| **landing** | `1` = check `/intro` landings + assets; `0` = skip (TOPS / mytops) | -| **canonical** | optional label after alias (e.g. `my.taler-ops.ch` → `taler-ops.ch`) | - -Then: - -```bash -./taler-monitoring.sh -d taler-ops.ch urls -``` - -Overrides (always win after profile load): - -```bash -./taler-monitoring.sh -d taler-ops.ch \ - --merchant https://my.taler-ops.ch \ - --exchange https://exchange.taler-ops.ch \ - --bank https://bank.taler-ops.ch urls -``` - -Helpers in `lib.sh`: `set_taler_stack`, `load_domain_profile`, `apply_taler_domain`. - -### Built-in profiles (see `domains.conf`) - -| Domain / alias | Bank | Exchange | Merchant | Currency | -|----------------|------|----------|----------|----------| -| `hacktivism.ch` / `koopa` | bank.hacktivism.ch | exchange.hacktivism.ch | taler.hacktivism.ch | GOA | +| Domain | Bank | Exchange | Merchant | Currency | +|--------|------|----------|----------|----------| +| `hacktivism.ch` (default) | bank.hacktivism.ch | exchange.hacktivism.ch | taler.hacktivism.ch | GOA | | `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 | -| `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. +| `taler-ops.ch` | bank.* (probe) | exchange.taler-ops.ch | backend.* (probe) | CHF | +| other | bank.DOMAIN | exchange.DOMAIN | backend/taler/merchant (probe) | any | **SSH only for koopa** (`hacktivism.ch` / `-d koopa`). @@ -104,9 +52,8 @@ Other domains: never SSH. Optional **e2e** aborts cleanly on login/KYC. | | Local (koopa) | Remote | |--|---------------|--------| -| **ATM withdraw** | 20 · 50 · 100 · 200 · **4200** (paivana) | 10 · 20 · 50 | +| **ATM withdraw** | 20 · 50 · 100 · 200 | 10 · 20 · 50 | | **Pay ladder** | 0.01 … 10 | 0.01 … 1 | -| **Paivana** | HTTP paywall + template pay **GOA:4200** (`goa-shop` / `paivana`) | skipped | ```bash ./taler-monitoring.sh e2e @@ -119,10 +66,6 @@ E2E_VARIABLE=0 WITHDRAW_AMT=GOA:50 PAY_AMT=GOA:1 ./taler-monitoring.sh e2e # s # E2E_SHOP_PRODUCTS lines: id|Product name|GOA:amount # E2E_SHOP_PICK_N=2 # (landing QR = taler://pay-template/…/{id}; popup = live taler://pay after POST templates/{id}) -# Paivana paywall (local GOA only): -# E2E_PAIVANA=1 (default) PAIVANA_PUBLIC=https://paivana.hacktivism.ch -# E2E_PAIVANA_TEMPLATE=paivana E2E_PAIVANA_AMOUNT=GOA:4200 E2E_PAIVANA_INSTANCE=goa-shop -# E2E_PAIVANA=0 # skip # remote secrets: # E2E_BANK_ADMIN_PASS=… E2E_MERCHANT_TOKEN=… ``` diff --git a/scripts/taler-monitoring/TESTS.md b/scripts/taler-monitoring/TESTS.md index 6999b77..ad1e6d5 100644 --- a/scripts/taler-monitoring/TESTS.md +++ b/scripts/taler-monitoring/TESTS.md @@ -43,17 +43,12 @@ IDs are assigned **in run order** within the area (`set_area` resets the counter | www-… | **merchant `/terms`** body (dual-currency notice) | | www-… | **merchant `/privacy`** body (must not be `not configured`) | | www-… | merchant `/terms/` redirect | -| www-… | **landing (aggregated per site)**: one line for bank/merchant/exchange (`/intro` + assets + own/external link counts); failures listed as samples; soft external/shop assets compact | -| www-… | cross-links: one line (4 intros) on local stack | -| www-… | bank demo-withdraw + shop assets: one line (+ soft shop-pay if missing) | -| www-… | **bank `/intro/demo-withdraw.json`** → `taler://withdraw/HOST:PORT/taler-integration/…` + integration op HTTP 200 | | www-… | **landing exposed links** (bank / merchant / exchange): parse each `/intro/` HTML, probe every own-stack `https://` + root-relative `href`/`src`/`content`, soft-check external stores/docs | | www-… | landing static: `qrcode.min.js`, `og-goa-shop.png`, `qr-logo.png`, shop-pay.js/css | | www-… | cross-links between bank ↔ merchant ↔ exchange intros (local stack) | | www-… | **bank `/intro/demo-withdraw.json`** → `taler://withdraw/HOST/taler-integration/…` (no default `:443`/`:80`; non-default port OK) + integration op HTTP 200 | | www-… | bank `/intro/auto-account.json` (earlier) → same withdraw shape, **no payto_uri**, login at `/webui/` | -| www-… | **performance** (outside-in RTT): bank/exchange/merchant `/config`, keys, webui, intro — ms; WARN ≥ `PERF_WARN_MS` (8000); ERROR ≥ `PERF_FAIL_MS` (20000) | -| www-… | **landing load stats**: `/intro/stats.json` → loadavg, container RSS, in-container probe ms (public; SSH container cat fallback); warn if stale/missing | +| www-… | **performance** (outside-in): public HTTPS RTT for bank `/config`, `/taler-integration/config`, `/webui/`, `/intro/`, `stats.json`; exchange `/config`, `/keys`, `/intro/`; merchant `/config`, `/webui/`, `/intro/` — report ms; WARN ≥ `PERF_WARN_MS` (default 8000); **ERROR ≥ `PERF_FAIL_MS` (default 20000)** | **Legal docs rule:** HTTP 200, non-empty body, not plain `not configured`, not merchant API JSON `code:21`. On local stack, optional content needle (terms/privacy/FADP/GOA…). @@ -143,8 +138,6 @@ Without SSH (`SKIP_SSH=1` or remote domain): still runs outside-in repo checks; ## e2e — payment path (`./taler-monitoring.sh e2e`) -Local GOA also: **ATM includes GOA:4200**, then **paivana** (HTTP 302 on `PAIVANA_PUBLIC` + public template pay `paivana` / GOA:4200 on `goa-shop`). Disable with `E2E_PAIVANA=0`. - | ID | Step (approx.) | |----|----------------| | e2e-001 | budget info | diff --git a/scripts/taler-monitoring/check_e2e.sh b/scripts/taler-monitoring/check_e2e.sh index 8c4670e..aa1eab6 100755 --- a/scripts/taler-monitoring/check_e2e.sh +++ b/scripts/taler-monitoring/check_e2e.sh @@ -216,14 +216,14 @@ except Exception: print("")' 2>/dev/null || true) # E2E_ATM_MAX=N # try at most N ATM withdraws (budget) # --------------------------------------------------------------------------- : "${E2E_VARIABLE:=1}" -: "${E2E_ATM_MAX:=5}" +: "${E2E_ATM_MAX:=4}" if [ "$E2E_REMOTE" = "1" ]; then # remote: still ATM-shaped but smaller notes; keep cheap : "${E2E_WITHDRAW_VALUES:=10 20 50}" : "${E2E_PAY_VALUES:=0.01 0.05 0.1 1}" else - # local GOA: classic ATM notes + 4200 for paivana paywall template - : "${E2E_WITHDRAW_VALUES:=20 50 100 200 4200}" + # local GOA: classic ATM denominations + : "${E2E_WITHDRAW_VALUES:=20 50 100 200}" : "${E2E_PAY_VALUES:=0.01 0.05 0.1 0.5 1 2 5 10}" fi @@ -275,24 +275,12 @@ PAY_AMT=$(printf '%s' "$PAY_LIST" | awk '{print $1}') if [ "$E2E_VARIABLE" = "1" ]; then n_w=$(printf '%s' "$WITHDRAW_LIST" | wc -w | tr -d ' ') n_p=$(printf '%s' "$PAY_LIST" | wc -w | tr -d ' ') - need=$(( 50 + n_w * 40 + n_p * 20 + 60 )) # + room for paivana pay + need=$(( 40 + n_w * 35 + n_p * 20 )) if [ "${E2E_TIMEOUT}" -lt "$need" ]; then E2E_TIMEOUT=$need fi - # cap ATM attempts but always keep CUR:4200 if listed (paivana) - WITHDRAW_LIST=$( - printf '%s' "$WITHDRAW_LIST" | tr ' ' '\n' | awk -v max="$E2E_ATM_MAX" -v big="${CUR}:4200" ' - NF==0 { next } - $0==big { has=1; next } - { small[++n]=$0 } - END { - keep = max - (has ? 1 : 0) - if (keep < 0) keep = 0 - for (i = 1; i <= n && i <= keep; i++) printf "%s ", small[i] - if (has) printf "%s", big - print "" - }' | sed 's/ *$//' - ) + # cap ATM attempts + WITHDRAW_LIST=$(printf '%s' "$WITHDRAW_LIST" | tr ' ' '\n' | head -n "$E2E_ATM_MAX" | tr '\n' ' ' | sed 's/ *$//') fi BANK_HOST=$(python3 -c 'from urllib.parse import urlparse; print(urlparse("'"$BANK_PUBLIC"'").hostname or "bank")' 2>/dev/null || echo bank) @@ -302,7 +290,7 @@ WDB="$SCRATCH/wallet.sqlite3" METRICS_DIR="${METRICS_DIR:-$SCRATCH/metrics}" mkdir -p "$METRICS_DIR" export METRICS_DIR CUR="${CUR:-${EXPECT_CURRENCY:-GOA}}" WDB -export PATH="${HOME}/.local/bin:${HOME}/taler/opt/taler-wallet-cli/usr/bin:/opt/homebrew/bin:/usr/local/bin:$PATH" +export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH" # Always dump balances on any exit (timeout, blocker, signal, success) trap 'ec=$?; e2e_finish "$ec"; rm -rf "$SCRATCH"; exit "$ec"' EXIT @@ -331,41 +319,7 @@ WALLET_CLI=$(find_wallet_cli) || { blocker "prereq" "taler-wallet-cli not found (set WALLET_CLI=)" exit 1 } -# Implementation version (--version) + wallet-core API ranges (version command) -WALLET_IMPL_VER=$( - node "$WALLET_CLI" --version 2>/dev/null | head -1 | tr -d '\r' || true -) -WALLET_CORE_VER=$( - _wver_db=$(mktemp "${TMPDIR:-/tmp}/wver.XXXXXX.sqlite3" 2>/dev/null || echo "${TMPDIR:-/tmp}/wver-$$.sqlite3") - node "$WALLET_CLI" --wallet-db="$_wver_db" --no-throttle --skip-defaults version 2>/dev/null \ - | python3 -c ' -import json,re,sys -raw=sys.stdin.read() -d=None -for m in re.finditer(r"\{", raw): - try: - d=json.loads(raw[m.start():]) - if isinstance(d, dict) and "version" in d: - break - except Exception: - d=None -if not isinstance(d, dict): - sys.exit(0) -parts=[] -# wallet-core libversion + protocol ranges used against exchange/merchant/bank -for k in ("version","implementationSemver","exchange","merchant","bank","bankIntegrationApiRange","corebankApiRange"): - if k in d and d[k] is not None: - parts.append("%s=%s" % (k, d[k])) -print(" ".join(parts)) -' 2>/dev/null || true - rm -f "$_wver_db" "$_wver_db"-* 2>/dev/null || true -) -ok "wallet-cli" "${WALLET_IMPL_VER:-?} · ${WALLET_CLI}" -if [ -n "${WALLET_CORE_VER:-}" ]; then - info "wallet-core" "$WALLET_CORE_VER" -else - info "wallet-core" "version details unavailable (impl ${WALLET_IMPL_VER:-?})" -fi +ok "wallet-cli ($WALLET_CLI)" info "e2e mode" "$([ "$E2E_REMOTE" = "1" ] && echo "remote/public domain (no SSH)" || echo "local koopa stack")" info "currency" "$CUR" info "ATM withdraw ladder" "$WITHDRAW_LIST (credit $CREDIT_AMT)" @@ -1296,104 +1250,11 @@ EOF fi fi -# --------------------------------------------------------------------------- -section "e2e · paivana paywall (template GOA:4200)" -# --------------------------------------------------------------------------- -# Public paywall: https://paivana.hacktivism.ch → 302 to merchant template "paivana". -# Requires spendable ≥ 4200 GOA (ATM ladder includes GOA:4200 by default). -: "${PAIVANA_PUBLIC:=https://paivana.hacktivism.ch}" -: "${E2E_PAIVANA:=1}" -: "${E2E_PAIVANA_TEMPLATE:=paivana}" -: "${E2E_PAIVANA_AMOUNT:=GOA:4200}" -: "${E2E_PAIVANA_INSTANCE:=goa-shop}" -PAIVANA_OK=0 -PAIVANA_REPORT="" -if [ "$E2E_REMOTE" = "1" ] || [ "${CUR:-}" != "GOA" ] || [ "${E2E_PAIVANA}" = "0" ]; then - info "paivana" "SKIPPED (remote, non-GOA, or E2E_PAIVANA=0)" - PAIVANA_REPORT="SKIP" -else - PAIVANA_PUBLIC="${PAIVANA_PUBLIC%/}" - # HTTP: paywall front must redirect into template flow (or serve well-known) - hdr=$(curl -skS -m 12 -D - -o /dev/null "$PAIVANA_PUBLIC/" 2>/dev/null || true) - pcode=$(printf '%s' "$hdr" | awk 'BEGIN{c="000"} /^HTTP/{c=$2} END{print c}') - loc=$(printf '%s' "$hdr" | awk 'BEGIN{IGNORECASE=1} /^location:/{sub(/\r$/,""); sub(/^location:[[:space:]]*/,""); print; exit}') - case "$pcode" in - 301|302|303|307|308) - if printf '%s' "$loc" | grep -qiE 'paivana|templates|well-known'; then - ok "paivana HTTP" "HTTP $pcode → ${loc:0:120}" - else - ok "paivana HTTP" "HTTP $pcode redirect (Location: ${loc:0:80})" - fi - ;; - 200) - warn "paivana HTTP" "HTTP 200 without paywall redirect — unexpected for locked site" - ;; - *) - fail "paivana HTTP" "HTTP ${pcode:-000} on $PAIVANA_PUBLIC/ (want 302 to template)" - PAIVANA_REPORT="HTTP_FAIL" - ;; - esac - - # Ensure wallet can cover 4200 (extra ATM if ladder did not fund enough) - pay_need=$(python3 -c 'import sys; print(float(sys.argv[1].split(":",1)[-1]))' "$E2E_PAIVANA_AMOUNT" 2>/dev/null || echo 4200) - av_now=$(wallet_avail_num) - if ! python3 -c "import sys; sys.exit(0 if float(sys.argv[1]) + 1e-9 >= float(sys.argv[2]) else 1)" "$av_now" "$pay_need" 2>/dev/null; then - info "paivana" "avail ${CUR}:${av_now} < ${pay_need} — ATM withdraw ${E2E_PAIVANA_AMOUNT}" - e2e_over && warn "paivana" "budget low before 4200 withdraw" - set +e - e2e_one_withdraw "$E2E_PAIVANA_AMOUNT" - wc=$? - set -e - if [ "$wc" = "0" ]; then - WITHDRAW_OK=1 - WITHDRAW_OK_N=$((WITHDRAW_OK_N + 1)) - WITHDRAW_REPORT="${WITHDRAW_REPORT}${WITHDRAW_REPORT:+ }${E2E_PAIVANA_AMOUNT}=OK(paivana)" - elif [ "$wc" = "2" ]; then - WITHDRAW_LAG_N=$((WITHDRAW_LAG_N + 1)) - WITHDRAW_REPORT="${WITHDRAW_REPORT}${WITHDRAW_REPORT:+ }${E2E_PAIVANA_AMOUNT}=LAG(paivana)" - else - WITHDRAW_FAIL_N=$((WITHDRAW_FAIL_N + 1)) - WITHDRAW_REPORT="${WITHDRAW_REPORT}${WITHDRAW_REPORT:+ }${E2E_PAIVANA_AMOUNT}=FAIL(paivana)" - fi - wait_wallet_balance "$(python3 -c "print(max(0, $pay_need - 1))" 2>/dev/null || echo 4199)" 12 3 || true - av_now=$(wallet_avail_num) - fi - - if ! python3 -c "import sys; sys.exit(0 if float(sys.argv[1]) + 1e-9 >= float(sys.argv[2]) else 1)" "$av_now" "$pay_need" 2>/dev/null; then - warn "paivana" "skip pay — insufficient avail ${CUR}:${av_now} (need ${pay_need})" - PAIVANA_REPORT="${PAIVANA_REPORT:+$PAIVANA_REPORT+}SKIP(bal)" - else - _E2E_INST_SAVE="$INST" - INST="${E2E_PAIVANA_INSTANCE}" - set +e - e2e_one_pay_public_template \ - "${E2E_PAIVANA_TEMPLATE}" \ - "Paivana paywall" \ - "${E2E_PAIVANA_AMOUNT}" - pc=$? - set -e - INST="$_E2E_INST_SAVE" - unset _E2E_INST_SAVE - if [ "$pc" = "0" ]; then - PAIVANA_OK=1 - PAY_OK=1 - PAY_OK_N=$((PAY_OK_N + 1)) - PAIVANA_REPORT="${PAIVANA_REPORT:+$PAIVANA_REPORT+}PAY_OK" - ok "paivana" "template ${E2E_PAIVANA_TEMPLATE} paid ${E2E_PAIVANA_AMOUNT}" - else - PAIVANA_REPORT="${PAIVANA_REPORT:+$PAIVANA_REPORT+}PAY_FAIL" - warn "paivana" "template pay failed (${E2E_PAIVANA_TEMPLATE} · ${E2E_PAIVANA_AMOUNT})" - fi - fi - info "paivana summary" "${PAIVANA_REPORT:-?} · instance ${E2E_PAIVANA_INSTANCE}" -fi - section "e2e · report" info "user" "$USER" info "ATM withdraws" "$WITHDRAW_REPORT" info "payments" "$PAY_REPORT" info "goa-shop" "${SHOP_REPORT:-(n/a)}" -info "paivana" "${PAIVANA_REPORT:-(n/a)}" info "final balance" "$(fmt_bal "$SCRATCH/bal-live.out" 2>/dev/null || echo "(n/a)")" info "scratch" "$SCRATCH" # Success if we had coins and at least one pay, OR coins + only pay skips (nothing affordable) diff --git a/scripts/taler-monitoring/check_urls.sh b/scripts/taler-monitoring/check_urls.sh index c5cd78d..b974603 100755 --- a/scripts/taler-monitoring/check_urls.sh +++ b/scripts/taler-monitoring/check_urls.sh @@ -207,13 +207,9 @@ PY fi fi fi -if [ "${CHECK_LANDING:-1}" = "1" ]; then - check_url_soft "exchange /intro/" 200 "$EXCHANGE_PUBLIC/intro/" - # Root should land on intro (302/301 then 200 on follow is checked separately) - check_url_soft "exchange /" 302,301,200 "$EXCHANGE_PUBLIC/" -else - info "exchange /intro" "skipped (CHECK_LANDING=0 · no public landings for this stack)" -fi +check_url_soft "exchange /intro/" 200 "$EXCHANGE_PUBLIC/intro/" +# Root should land on intro (302/301 then 200 on follow is checked separately) +check_url_soft "exchange /" 302,301,200 "$EXCHANGE_PUBLIC/" # --------------------------------------------------------------------------- # Performance — outside-in public HTTPS latency (this runner, not loopback) @@ -267,137 +263,20 @@ check_perf() { # Bank first (wallet-critical paths before UI chrome) check_perf "perf bank /taler-integration/config" "$BANK_PUBLIC/taler-integration/config" check_perf "perf bank /config" "$BANK_PUBLIC/config" -if [ "${CHECK_LANDING:-1}" = "1" ]; then - check_perf "perf bank /intro/" "$BANK_PUBLIC/intro/" - check_perf "perf bank /intro/stats.json" "$BANK_PUBLIC/intro/stats.json" 200 -fi +check_perf "perf bank /intro/" "$BANK_PUBLIC/intro/" +check_perf "perf bank /intro/stats.json" "$BANK_PUBLIC/intro/stats.json" 200 check_perf "perf bank /webui/" "$BANK_PUBLIC/webui/" 200,301,302 # Exchange check_perf "perf exchange /config" "$EXCHANGE_PUBLIC/config" check_perf "perf exchange /keys" "$EXCHANGE_PUBLIC/keys" -if [ "${CHECK_LANDING:-1}" = "1" ]; then - check_perf "perf exchange /intro/" "$EXCHANGE_PUBLIC/intro/" -fi +check_perf "perf exchange /intro/" "$EXCHANGE_PUBLIC/intro/" # Merchant check_perf "perf merchant /config" "$MERCHANT_PUBLIC/config" check_perf "perf merchant /webui/" "$MERCHANT_PUBLIC/webui/" 200,301,302 -if [ "${CHECK_LANDING:-1}" = "1" ]; then - check_perf "perf merchant /intro/" "$MERCHANT_PUBLIC/intro/" -fi +check_perf "perf merchant /intro/" "$MERCHANT_PUBLIC/intro/" -info "perf note" "RTT measured from this host (outside-in)" - -# --------------------------------------------------------------------------- -# Landing load stats (stats.json written *inside* containers, usually public). -# Prefer HTTPS /intro/stats.json (no SSH). If missing and SSH works, cat from -# the container. Report loadavg + RSS + in-container probe ms — one line each. -# --------------------------------------------------------------------------- -: "${STATS_STALE_SECS:=900}" # warn if generated_at older than 15m - -_fetch_landing_stats_json() { - # $1=name bank|exchange|merchant $2=base URL → writes $tmp/stats-$1.json, exit 0 if ok - local name="$1" base="$2" - local f="$tmp/stats-${name}.json" - local code ctr path - rm -f "$f" - code=$(http_body "${base}/intro/stats.json" "$f" 2>/dev/null || echo 000) - if [ "$code" = "200" ] && [ -s "$f" ]; then - return 0 - fi - # Optional inside-container fallback (no public path or empty) - if [ "${LOCAL_STACK:-0}" = "1" ] && [ "${SKIP_SSH:-0}" != "1" ] && koopa_ssh_ok 2>/dev/null; then - case "$name" in - bank) ctr=taler-hacktivism-bank; path=/var/www/bank-landing/stats.json ;; - exchange) ctr=taler-hacktivism-exchange-ansible; path=/var/www/exchange-landing/stats.json ;; - merchant) ctr=taler-hacktivism; path=/var/www/merchant-landing/stats.json ;; - *) return 1 ;; - esac - if koopa_ssh_run 12 "podman exec ${ctr} cat ${path} 2>/dev/null" >"$f" 2>/dev/null \ - && [ -s "$f" ]; then - return 0 - fi - fi - return 1 -} - -report_landing_load_stats() { - local name="$1" base="$2" - local f="$tmp/stats-${name}.json" - local line age_s - - if ! _fetch_landing_stats_json "$name" "$base"; then - if [ "${CHECK_LANDING:-1}" = "1" ] || [ "${LOCAL_STACK:-0}" = "1" ]; then - warn "perf ${name} landing-stats" "stats.json not available (public or SSH)" - fi - return - fi - - line=$(python3 - "$f" "${STATS_STALE_SECS}" <<'PY' 2>/dev/null || true -import json, sys, time -path, stale = sys.argv[1], int(sys.argv[2]) -try: - d = json.load(open(path)) -except Exception as e: - print("ERR parse:" + str(e)[:80]) - sys.exit(0) -if not d.get("ok", True): - print("ERR ok=false " + str(d.get("error") or "")[:80]) - sys.exit(0) -p = d.get("performance") or {} -if not isinstance(p, dict) or not p: - print("ERR no performance block") - sys.exit(0) -mem = p.get("memory") if isinstance(p.get("memory"), dict) else {} -rss = mem.get("container_rss_human") or mem.get("proc_sum_rss_human") or "?" -load = p.get("loadavg") or "?" -# latency fields differ by site -bits = [] -for k in ("config_ms", "integration_ms", "webui_ms", "keys_ms", "terms_ms"): - if k in p and p[k] is not None: - bits.append("%s=%sms" % (k.replace("_ms", ""), p[k])) -lat = " ".join(bits) if bits else "latency=?" -gen = d.get("generated_at_human") or d.get("generated_at") or "?" -# staleness -age = "" -try: - gu = d.get("generated_at_unix") - if gu is not None: - age_s = int(time.time()) - int(gu) - age = " age=%ss" % age_s - if age_s > stale: - print("STALE loadavg=%s RSS=%s %s gen=%s%s" % (load, rss, lat, gen, age)) - sys.exit(0) -except Exception: - pass -print("OK loadavg=%s RSS=%s %s gen=%s%s" % (load, rss, lat, gen, age)) -PY -) - - case "$line" in - OK\ *) - ok "perf ${name} landing-stats" "${line#OK }" - ;; - STALE\ *) - warn "perf ${name} landing-stats" "stale · ${line#STALE }" - ;; - ERR\ *) - warn "perf ${name} landing-stats" "${line#ERR }" - ;; - *) - warn "perf ${name} landing-stats" "unreadable stats.json" - ;; - esac -} - -if [ "${CHECK_LANDING:-1}" = "1" ] || [ "${LOCAL_STACK:-0}" = "1" ]; then - section "www · performance · landing load stats (stats.json · in-container probes)" - report_landing_load_stats "bank" "$BANK_PUBLIC" - report_landing_load_stats "exchange" "$EXCHANGE_PUBLIC" - report_landing_load_stats "merchant" "$MERCHANT_PUBLIC" - info "perf landing-stats note" "from /intro/stats.json (public); SSH container fallback if needed" -fi # Rollup + optional JSON for metrics_print_overall if [ -s "$PERF_TSV" ]; then PERF_JSON="$tmp/perf-summary.json" @@ -590,9 +469,7 @@ PY rm -f /tmp/alt-mer.$$ # Follow each exchange listed in merchant /config and require its /config alt_unit_names check_merchant_listed_exchanges_alt_units "$tmp/mc.json" - if [ "${CHECK_LANDING:-1}" = "1" ]; then - check_url_soft "merchant /intro/" 200 "$MERCHANT_PUBLIC/intro/" - fi + check_url_soft "merchant /intro/" 200 "$MERCHANT_PUBLIC/intro/" check_url_soft "merchant /webui/" 200 "$MERCHANT_PUBLIC/webui/" check_url_soft "merchant /" 302,301,200 "$MERCHANT_PUBLIC/" fi @@ -606,92 +483,49 @@ case "$code" in *) warn "merchant /terms/" "HTTP $code (expect 302 → /terms)" ;; esac -# --------------------------------------------------------------------------- -# Paivana paywall (local GOA stack) — public front only; pay path is e2e -# --------------------------------------------------------------------------- -if [ "${LOCAL_STACK:-1}" = "1" ] && [ "${E2E_PAIVANA:-1}" != "0" ]; then - section "www · paivana paywall" - : "${PAIVANA_PUBLIC:=https://paivana.hacktivism.ch}" - PAIVANA_PUBLIC="${PAIVANA_PUBLIC%/}" - hdr=$(curl -skS -m "${TIMEOUT}" -D - -o /dev/null "${PAIVANA_PUBLIC}/" 2>/dev/null || true) - pcode=$(printf '%s' "$hdr" | awk 'BEGIN{c="000"} /^HTTP/{c=$2} END{print c}') - loc=$(printf '%s' "$hdr" | awk 'BEGIN{IGNORECASE=1} /^location:/{sub(/\r$/,""); sub(/^location:[[:space:]]*/,""); print; exit}') - case "$pcode" in - 301|302|303|307|308) - if printf '%s' "$loc" | grep -qiE 'paivana|templates|well-known'; then - ok "paivana /" "HTTP $pcode → template flow" - else - ok "paivana /" "HTTP $pcode redirect" - fi - info "paivana Location" "${loc:0:140}" - ;; - 200) - warn "paivana /" "HTTP 200 (expected paywall redirect to template)" - ;; - *) - warn "paivana /" "HTTP ${pcode:-000} — ${PAIVANA_PUBLIC}/ (e2e pay may still work via template)" - ;; - esac -fi - # --------------------------------------------------------------------------- # Landing pages: every HTTPS link exposed on bank / merchant / exchange intros # + required static assets + bank withdraw mint (taler://withdraw only) -# Skipped when CHECK_LANDING=0 (e.g. taler-ops.ch — no GOA-style landings). # --------------------------------------------------------------------------- -if [ "${CHECK_LANDING:-1}" != "1" ]; then - section "www · landing pages" - info "landing checks" "skipped (CHECK_LANDING=0 · stack has no public /intro landings)" - summary - exit 0 -fi - section "www · landing exposed links · bank / merchant / exchange" -# Probe one URL: print code to stdout (200 after following redirects counts as 200). -# Sets _landing_code. Exit 0 if OK (200 or redirect→200), 1 otherwise. -_landing_probe() { - local url="$1" +# Known-good landing static paths (relative to each host base) +# Checked even if HTML parse misses them. +check_landing_asset() { + local label="$1" url="$2" soft="${3:-0}" local code code=$(http_code "$url") case "$code" in - 200) _landing_code=200; return 0 ;; + 200) ok "$label" "HTTP 200 · $url" ;; 301|302|303|307|308) - code=$(curl -skS --max-redirs 5 -L -m "${TIMEOUT}" -o /dev/null -w '%{http_code}' "$url" 2>/dev/null || echo 000) - _landing_code="$code" - [ "$code" = "200" ] && return 0 - return 1 + # follow once for assets that redirect + code=$(curl -skS --max-redirs 3 -L -m "${TIMEOUT}" -o /dev/null -w '%{http_code}' "$url" 2>/dev/null || echo 000) + if [ "$code" = "200" ]; then + ok "$label" "HTTP redirect→200 · $url" + elif [ "$soft" = "1" ]; then + warn "$label" "HTTP $code — $url" + else + fail "$label" "HTTP $code after redirect — $url" + fi ;; *) - _landing_code="$code" - return 1 + if [ "$soft" = "1" ]; then + warn "$label" "HTTP $code — $url" + else + fail "$label" "HTTP $code — $url" + fi ;; esac } -# Known-good landing static paths — one report line via caller aggregate, or -# soft=1 single warn. Returns 0 if ok. -check_landing_asset() { - local label="$1" url="$2" soft="${3:-0}" - if _landing_probe "$url"; then - return 0 - fi - if [ "$soft" = "1" ]; then - warn "$label" "HTTP ${_landing_code:-?} — $url" - else - fail "$label" "HTTP ${_landing_code:-?} — $url" - fi - return 1 -} - -# Soft external: never ERROR; used only for failures in aggregated external probe. +# Soft external (app stores / upstream docs): WARN if down, never ERROR check_external_soft() { local label="$1" url="$2" local code code=$(curl -skS --max-redirs 5 -L -m "${TIMEOUT}" -o /dev/null -w '%{http_code}' "$url" 2>/dev/null || echo 000) case "$code" in - 200|204|301|302|303|307|308) return 0 ;; - *) warn "$label" "HTTP $code · $url"; return 1 ;; + 200|204|301|302|303|307|308) ok "$label" "HTTP $code · $url" ;; + *) warn "$label" "HTTP $code (external soft) · $url" ;; esac } @@ -788,98 +622,76 @@ check_one_landing() { local html="$tmp/landing-${name}.html" local pref="$tmp/urls-${name}" local code n own_n ext_n - local a_ok=0 a_fail=0 a_soft=0 - local own_ok=0 own_fail=0 - local ext_ok=0 ext_fail=0 - local fail_sample="" soft_sample="" - code=$(http_body "${base}/intro/" "$html") if [ "$code" != "200" ]; then if [ "${LOCAL_STACK:-1}" = "1" ]; then - fail "landing ${name}" "/intro/ HTTP $code — skip assets/links" + fail "landing ${name} /intro/" "HTTP $code" else - warn "landing ${name}" "/intro/ HTTP $code — skip assets/links" + warn "landing ${name} /intro/" "HTTP $code" fi return fi + ok "landing ${name} /intro/" "HTTP 200 · $(wc -c <"$html" | tr -d ' ') bytes" - # Required static assets (hard: qrcode + og; soft: qr-logo) - for url in \ - "${base}/intro/qrcode.min.js" \ - "${base}/intro/og-goa-shop.png" - do - if _landing_probe "$url"; then - a_ok=$((a_ok + 1)) - else - a_fail=$((a_fail + 1)) - fail_sample="${fail_sample}${fail_sample:+; }HTTP ${_landing_code} $url" - fi - done - if _landing_probe "${base}/intro/qr-logo.png"; then - a_ok=$((a_ok + 1)) - else - a_soft=$((a_soft + 1)) - soft_sample="${soft_sample}${soft_sample:+; }HTTP ${_landing_code} qr-logo.png" - fi + # Required static assets (hard on local) + check_landing_asset "landing ${name} qrcode.min.js" "${base}/intro/qrcode.min.js" + check_landing_asset "landing ${name} og-goa-shop.png" "${base}/intro/og-goa-shop.png" + check_landing_asset "landing ${name} qr-logo.png" "${base}/intro/qr-logo.png" 1 n=$(extract_landing_urls "$base" "$html" "$pref" 2>/dev/null || echo "own=0 ext=0") + info "landing ${name} link extract" "$n" own_n=0 ext_n=0 [ -f "${pref}.own" ] && own_n=$(grep -c . "${pref}.own" 2>/dev/null || echo 0) [ -f "${pref}.ext" ] && ext_n=$(grep -c . "${pref}.ext" 2>/dev/null || echo 0) - # strip newlines from grep -c edge cases - own_n=${own_n//[^0-9]/} - ext_n=${ext_n//[^0-9]/} - own_n=${own_n:-0} - ext_n=${ext_n:-0} + if [ "${own_n:-0}" -lt 1 ]; then + fail "landing ${name} own-stack links" "none extracted from HTML" + else + ok "landing ${name} own-stack links" "${own_n} URLs to probe" + fi - # Probe own-stack URLs — count only; list failures + # Probe every own-stack URL from the page if [ -f "${pref}.own" ]; then while IFS= read -r u; do [ -n "$u" ] || continue - if _landing_probe "$u"; then - own_ok=$((own_ok + 1)) - else - own_fail=$((own_fail + 1)) - # keep a few samples (max ~3) - if [ "$own_fail" -le 3 ]; then - fail_sample="${fail_sample}${fail_sample:+; }own HTTP ${_landing_code} $u" - fi - fi - done < "${pref}.own" - fi - - # External: soft counts - if [ -f "${pref}.ext" ]; then - while IFS= read -r u; do - [ -n "$u" ] || continue - code=$(curl -skS --max-redirs 5 -L -m "${TIMEOUT}" -o /dev/null -w '%{http_code}' "$u" 2>/dev/null || echo 000) + # skip mint endpoints that create resources on GET if any (auto-account creates accounts) + case "$u" in + */intro/auto-account.json) + # shape checked separately; still require 200 GET + ;; + esac + code=$(http_code "$u") case "$code" in - 200|204|301|302|303|307|308) ext_ok=$((ext_ok + 1)) ;; + 200) ok "landing ${name} link" "HTTP 200 · $u" ;; + 301|302|303|307|308) + code=$(curl -skS --max-redirs 5 -L -m "${TIMEOUT}" -o /dev/null -w '%{http_code}' "$u" 2>/dev/null || echo 000) + if [ "$code" = "200" ]; then + ok "landing ${name} link" "redirect→200 · $u" + else + fail "landing ${name} link" "HTTP $code after redirect · $u" + fi + ;; + 405|501) + # some APIs reject wrong method — try GET already failed; soft note + fail "landing ${name} link" "HTTP $code · $u" + ;; *) - ext_fail=$((ext_fail + 1)) - if [ "$ext_fail" -le 3 ]; then - soft_sample="${soft_sample}${soft_sample:+; }ext HTTP $code $u" + if [ "${LOCAL_STACK:-1}" = "1" ]; then + fail "landing ${name} link" "HTTP $code · $u" + else + warn "landing ${name} link" "HTTP $code · $u" fi ;; esac - done < "${pref}.ext" + done < "${pref}.own" fi - # One primary line per landing - local detail - detail="/intro $(wc -c <"$html" | tr -d ' ')B · assets ${a_ok}/$((a_ok + a_fail + a_soft)) · own-links ${own_ok}/${own_n} · external ${ext_ok}/${ext_n}" - if [ "$a_fail" -gt 0 ] || [ "$own_fail" -gt 0 ] || [ "${own_n:-0}" -lt 1 ]; then - if [ "${LOCAL_STACK:-1}" = "1" ]; then - fail "landing ${name}" "$detail${fail_sample:+ · $fail_sample}" - else - warn "landing ${name}" "$detail${fail_sample:+ · $fail_sample}" - fi - else - ok "landing ${name}" "$detail" - fi - if [ "$a_soft" -gt 0 ] || [ "$ext_fail" -gt 0 ]; then - warn "landing ${name} soft" "${soft_sample:-soft issues}" + # External store / docs: soft + if [ -f "${pref}.ext" ]; then + while IFS= read -r u; do + [ -n "$u" ] || continue + check_external_soft "landing ${name} external" "$u" + done < "${pref}.ext" fi } @@ -887,40 +699,18 @@ check_one_landing "bank" "$BANK_PUBLIC" check_one_landing "merchant" "$MERCHANT_PUBLIC" check_one_landing "exchange" "$EXCHANGE_PUBLIC" -# Cross-links: one line +# Cross-links between the three landings (always on local stack) if [ "${LOCAL_STACK:-1}" = "1" ]; then - _cx_ok=0 - _cx_fail=0 - _cx_detail="" - for pair in \ - "bank→merchant|$MERCHANT_PUBLIC/intro/" \ - "bank→exchange|$EXCHANGE_PUBLIC/intro/" \ - "merchant→bank|$BANK_PUBLIC/intro/" \ - "exchange→bank|$BANK_PUBLIC/intro/" - do - _cx_name="${pair%%|*}" - _cx_url="${pair#*|}" - if _landing_probe "$_cx_url"; then - _cx_ok=$((_cx_ok + 1)) - else - _cx_fail=$((_cx_fail + 1)) - _cx_detail="${_cx_detail}${_cx_detail:+; }${_cx_name} HTTP ${_landing_code}" - fi - done - if [ "$_cx_fail" -eq 0 ]; then - ok "landing cross-links" "${_cx_ok}/4 intros reachable" - else - fail "landing cross-links" "${_cx_ok}/4 ok · ${_cx_detail}" - fi + check_landing_asset "cross bank→merchant intro" "$MERCHANT_PUBLIC/intro/" + check_landing_asset "cross bank→exchange intro" "$EXCHANGE_PUBLIC/intro/" + check_landing_asset "cross merchant→bank intro" "$BANK_PUBLIC/intro/" + check_landing_asset "cross exchange→bank intro" "$BANK_PUBLIC/intro/" fi -# Bank withdraw mint + shop assets — compact +# Bank-only: shared-pool withdraw mint + static withdraw files + shop assets if [ "${LOCAL_STACK:-1}" = "1" ] || [ -n "${BANK_PUBLIC:-}" ]; then - _ba_ok=0 - _ba_soft=0 - _ba_msg="" - if _landing_probe "$BANK_PUBLIC/intro/shop-pay.js"; then _ba_ok=$((_ba_ok + 1)); else _ba_soft=$((_ba_soft + 1)); _ba_msg="${_ba_msg}shop-pay.js; "; fi - if _landing_probe "$BANK_PUBLIC/intro/shop-pay.css"; then _ba_ok=$((_ba_ok + 1)); else _ba_soft=$((_ba_soft + 1)); _ba_msg="${_ba_msg}shop-pay.css; "; fi + check_landing_asset "bank shop-pay.js" "$BANK_PUBLIC/intro/shop-pay.js" 1 + check_landing_asset "bank shop-pay.css" "$BANK_PUBLIC/intro/shop-pay.css" 1 dw_code=$(http_body "$BANK_PUBLIC/intro/demo-withdraw.json" "$tmp/dw.json") case "$dw_code" in 200) @@ -930,42 +720,28 @@ if [ "${LOCAL_STACK:-1}" = "1" ] || [ -n "${BANK_PUBLIC:-}" ]; then [ "$wid" = "$dw_out" ] && wid= ok "bank /intro/demo-withdraw.json" "$dw_detail" if [ -n "$wid" ]; then - if _landing_probe "$BANK_PUBLIC/taler-integration/withdrawal-operation/${wid}"; then - _ba_ok=$((_ba_ok + 1)) - else - fail "landing bank withdraw-op" "HTTP ${_landing_code} · id=$wid" - fi + check_landing_asset "bank taler-integration withdraw op" \ + "$BANK_PUBLIC/taler-integration/withdrawal-operation/${wid}" fi - ok "landing bank withdraw/shop" "demo-withdraw + shop assets ok (${_ba_ok} checks)" else - fail "landing bank demo-withdraw" "invalid taler://withdraw shape" fail "bank /intro/demo-withdraw.json" "invalid taler://withdraw ($(tr '\n' ' ' <"$tmp/dw-val" | sed 's/[[:space:]]*$//'))" fi ;; 405|501|404|502|503|000) - fail "landing bank demo-withdraw" "HTTP $dw_code (want 200)" + fail "bank /intro/demo-withdraw.json" "HTTP $dw_code (want 200)" ;; *) if [ "${LOCAL_STACK:-1}" = "1" ]; then - fail "landing bank demo-withdraw" "HTTP $dw_code want 200" + fail "bank /intro/demo-withdraw.json" "HTTP $dw_code want 200" else - warn "landing bank demo-withdraw" "HTTP $dw_code" + warn "bank /intro/demo-withdraw.json" "HTTP $dw_code" fi ;; esac - if [ "$_ba_soft" -gt 0 ]; then - warn "landing bank shop assets" "${_ba_msg}soft-missing" - fi fi -# Merchant shop assets — one soft line -_ma=0 -_landing_probe "$MERCHANT_PUBLIC/intro/shop-pay.js" && _ma=$((_ma + 1)) -_landing_probe "$MERCHANT_PUBLIC/intro/shop-pay.css" && _ma=$((_ma + 1)) -if [ "$_ma" -eq 2 ]; then - ok "landing merchant shop assets" "shop-pay.js + .css" -else - warn "landing merchant shop assets" "${_ma}/2 present (soft)" -fi +# Merchant landing shop assets +check_landing_asset "merchant shop-pay.js" "$MERCHANT_PUBLIC/intro/shop-pay.js" 1 +check_landing_asset "merchant shop-pay.css" "$MERCHANT_PUBLIC/intro/shop-pay.css" 1 summary diff --git a/scripts/taler-monitoring/domains.conf b/scripts/taler-monitoring/domains.conf deleted file mode 100644 index 1cc12af..0000000 --- a/scripts/taler-monitoring/domains.conf +++ /dev/null @@ -1,46 +0,0 @@ -# taler-monitoring domain profiles -# -# When you add a stack, declare the three public endpoints here: -# name bank exchange merchant-backend currency local landing [canonical] -# -# - name: what -d / TALER_DOMAIN matches (aliases allowed as extra lines) -# - bank / exchange / merchant: hostname or full https:// URL -# - currency: GOA | KUDOS | CHF | … (empty = report only) -# - local: 1 = koopa SSH/inside/e2e stack; 0 = public-only -# - landing: 1 = check /intro landings + assets; 0 = skip (no GOA-style landings) -# - canonical: optional TALER_DOMAIN label after alias match -# -# CLI overrides after load: --bank --exchange --merchant --currency -# Alternate file: TALER_DOMAINS_CONF=/path/to/domains.conf - -# Local GOA (koopa) — landings matter -koopa bank.hacktivism.ch exchange.hacktivism.ch taler.hacktivism.ch GOA 1 1 hacktivism.ch -hacktivism bank.hacktivism.ch exchange.hacktivism.ch taler.hacktivism.ch GOA 1 1 hacktivism.ch -hacktivism.ch bank.hacktivism.ch exchange.hacktivism.ch taler.hacktivism.ch GOA 1 1 - -# Public demo (KUDOS) — has intro-style pages; keep soft landing checks -taler.net bank.demo.taler.net exchange.demo.taler.net backend.demo.taler.net KUDOS 0 1 demo.taler.net -demo.taler.net bank.demo.taler.net exchange.demo.taler.net backend.demo.taler.net KUDOS 0 1 - -# Public test stack (TESTKUDOS) — no GOA-style landings -test.taler.net bank.test.taler.net exchange.test.taler.net backend.test.taler.net TESTKUDOS 0 0 - -# TOPS CHF — multi-tenant merchant my.taler-ops.ch; no public GOA landings -taler-ops.ch bank.taler-ops.ch exchange.taler-ops.ch my.taler-ops.ch CHF 0 0 -my.taler-ops.ch bank.taler-ops.ch exchange.taler-ops.ch my.taler-ops.ch CHF 0 0 taler-ops.ch -stage.taler-ops.ch bank.stage.taler-ops.ch exchange.stage.taler-ops.ch my.stage.taler-ops.ch CHF 0 0 -my.stage.taler-ops.ch bank.stage.taler-ops.ch exchange.stage.taler-ops.ch my.stage.taler-ops.ch CHF 0 0 stage.taler-ops.ch - -# Franc Paysan (Infomaniak) — merchant host is monnaie.* (not taler./backend.) -# Prod: no monetary launch yet; stage uses TESTPAYSAN (public HTTPS landings + shops) -lefrancpaysan.ch bank.lefrancpaysan.ch exchange.lefrancpaysan.ch monnaie.lefrancpaysan.ch - 0 0 -monnaie.lefrancpaysan.ch bank.lefrancpaysan.ch exchange.lefrancpaysan.ch monnaie.lefrancpaysan.ch - 0 0 lefrancpaysan.ch -bank.lefrancpaysan.ch bank.lefrancpaysan.ch exchange.lefrancpaysan.ch monnaie.lefrancpaysan.ch - 0 0 lefrancpaysan.ch -exchange.lefrancpaysan.ch bank.lefrancpaysan.ch exchange.lefrancpaysan.ch monnaie.lefrancpaysan.ch - 0 0 lefrancpaysan.ch - -# Stage TESTPAYSAN — landings on / + farmer shops under stage.monnaie…/shops/ -# name bank exchange merchant currency local landing [canonical] -stage.lefrancpaysan.ch stage.bank.lefrancpaysan.ch stage.exchange.lefrancpaysan.ch stage.monnaie.lefrancpaysan.ch TESTPAYSAN 0 1 -stage.bank.lefrancpaysan.ch stage.bank.lefrancpaysan.ch stage.exchange.lefrancpaysan.ch stage.monnaie.lefrancpaysan.ch TESTPAYSAN 0 1 stage.lefrancpaysan.ch -stage.exchange.lefrancpaysan.ch stage.bank.lefrancpaysan.ch stage.exchange.lefrancpaysan.ch stage.monnaie.lefrancpaysan.ch TESTPAYSAN 0 1 stage.lefrancpaysan.ch -stage.monnaie.lefrancpaysan.ch stage.bank.lefrancpaysan.ch stage.exchange.lefrancpaysan.ch stage.monnaie.lefrancpaysan.ch TESTPAYSAN 0 1 stage.lefrancpaysan.ch diff --git a/scripts/taler-monitoring/lib.sh b/scripts/taler-monitoring/lib.sh index 5df0819..c215bd9 100755 --- a/scripts/taler-monitoring/lib.sh +++ b/scripts/taler-monitoring/lib.sh @@ -16,13 +16,10 @@ : "${MERCHANT_INSTANCE:=goa-demo-cp4zqk}" : "${WITHDRAW_AMT:=GOA:20}" # single-shot fallback; e2e ladder uses ATM notes : "${PAY_AMT:=GOA:0.01}" -: "${CREDIT_AMT:=GOA:4700}" # covers ATM ladder 20+50+100+200+4200 (paivana) +: "${CREDIT_AMT:=GOA:400}" # covers ATM ladder 20+50+100+200 : "${TIMEOUT:=12}" -: "${E2E_TIMEOUT:=55}" # whole e2e budget; skip rest when exceeded (e2e raises as needed) +: "${E2E_TIMEOUT:=55}" # whole e2e budget; skip rest when exceeded : "${E2E_PAY_SECS:=22}" # dedicated seconds for pay handle-uri (avoid Alarm clock) -# Local GOA: public paivana paywall (https://paivana.hacktivism.ch · template GOA:4200) -: "${PAIVANA_PUBLIC:=https://paivana.hacktivism.ch}" -: "${E2E_PAIVANA:=1}" # 0 = skip paivana section in e2e # Devtest: inject reserve credit via wire-gateway admin/add-incoming (optional). # Default off once wirewatch DNS works; set E2E_FAKE_INCOMING=1 to force. : "${E2E_FAKE_INCOMING:=0}" @@ -42,108 +39,17 @@ EXCHANGE_PUBLIC=${EXCHANGE_PUBLIC%/} MERCHANT_PUBLIC=${MERCHANT_PUBLIC%/} # --------------------------------------------------------------------------- -# Domain profiles → bank / exchange / merchant base URLs +# Domain presets → public bank / exchange / merchant base URLs # -# Single place to declare a stack: scripts/taler-monitoring/domains.conf -# (or TALER_DOMAINS_CONF). Each profile names the three public endpoints. +# TALER_DOMAIN=hacktivism.ch (default, GOA, local stack) +# TALER_DOMAIN=taler.net → demo.taler.net (KUDOS) +# TALER_DOMAIN=demo.taler.net +# TALER_DOMAIN=taler-ops.ch → exchange.taler-ops.ch (CHF; bank/merchant if up) +# TALER_DOMAIN=example.org → bank/exchange/backend|taler|merchant.example.org # -# CLI still wins after profile load: -# --bank URL --exchange URL --merchant URL --currency CODE -# Env: BANK_PUBLIC EXCHANGE_PUBLIC MERCHANT_PUBLIC EXPECT_CURRENCY -# -# Unknown domains fall back to heuristics (see apply_taler_domain). +# Explicit BANK_PUBLIC / EXCHANGE_PUBLIC / MERCHANT_PUBLIC still win if set +# *after* apply_taler_domain, or pass full URLs via --bank/--exchange/--merchant. # --------------------------------------------------------------------------- - -_MONITOR_LIB_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) -: "${TALER_DOMAINS_CONF:=${_MONITOR_LIB_DIR}/domains.conf}" - -# host_or_url → https://… (no trailing slash) -_to_https_base() { - local x="${1%/}" - case "$x" in - https://*|http://*) printf '%s' "$x" ;; - "") printf '' ;; - *) printf 'https://%s' "$x" ;; - esac -} - -# 1 = check GOA-style /intro landing pages (assets, link crawl, demo-withdraw). -# 0 = skip (e.g. taler-ops.ch / mytops — no public landings). -: "${CHECK_LANDING:=1}" - -# Declare bank + exchange + merchant (+ currency, local stack, landing, domain id). -# Usage: -# set_taler_stack BANK EXCHANGE MERCHANT [CURRENCY] [LOCAL 0|1] [LANDING 0|1] [TALER_DOMAIN] -# BANK/EXCHANGE/MERCHANT: hostname or full URL -set_taler_stack() { - local bank="${1:-}" exchange="${2:-}" merchant="${3:-}" - local currency="${4:-}" local_stack="${5:-0}" landing="${6:-}" domain_id="${7:-}" - - BANK_PUBLIC=$(_to_https_base "$bank") - EXCHANGE_PUBLIC=$(_to_https_base "$exchange") - MERCHANT_PUBLIC=$(_to_https_base "$merchant") - # currency "-" or empty → report-only (do not force GOA) - if [ -n "$currency" ] && [ "$currency" != "-" ]; then - EXPECT_CURRENCY="$currency" - elif [ "$currency" = "-" ]; then - EXPECT_CURRENCY="" - fi - LOCAL_STACK="$local_stack" - if [ "$LOCAL_STACK" = "1" ]; then - SKIP_SSH=0 - else - SKIP_SSH=1 - fi - # default: landings only matter on local GOA stack - if [ -n "$landing" ]; then - CHECK_LANDING="$landing" - elif [ "$LOCAL_STACK" = "1" ]; then - CHECK_LANDING=1 - else - CHECK_LANDING=0 - fi - [ -n "$domain_id" ] && TALER_DOMAIN="$domain_id" - - BANK_PUBLIC=${BANK_PUBLIC%/} - EXCHANGE_PUBLIC=${EXCHANGE_PUBLIC%/} - MERCHANT_PUBLIC=${MERCHANT_PUBLIC%/} -} - -# Load first matching profile from domains.conf. -# Fields (whitespace-separated; # comments; blank lines ignored): -# name bank exchange merchant currency local[0|1] landing[0|1] [canonical_domain] -# Returns 0 if found, 1 if not. -load_domain_profile() { - local want="$1" conf="${TALER_DOMAINS_CONF:-}" - local line name bank exchange merchant currency local_stack landing canon - [ -n "$want" ] || return 1 - [ -n "$conf" ] && [ -f "$conf" ] || return 1 - - while IFS= read -r line || [ -n "$line" ]; do - line="${line%%#*}" - # shellcheck disable=SC2086 - set -- $line - [ $# -ge 5 ] || continue - name="$1" - [ "$name" = "$want" ] || continue - bank="$2" - exchange="$3" - merchant="$4" - currency="$5" - local_stack="${6:-0}" - landing="${7:-}" - canon="${8:-$name}" - # Backward compat: old 7th field was canonical domain (contains a dot) - if [ -n "$landing" ] && [[ "$landing" == *.* && "$landing" != "0" && "$landing" != "1" ]]; then - canon="$landing" - landing="" - fi - set_taler_stack "$bank" "$exchange" "$merchant" "$currency" "$local_stack" "$landing" "$canon" - return 0 - done <"$conf" - return 1 -} - _normalize_domain() { local d="$1" d="${d#https://}" @@ -154,7 +60,7 @@ _normalize_domain() { # e.g. bank.demo.taler.net → demo.taler.net, taler.hacktivism.ch → hacktivism.ch # but NOT taler.net → net case "$d" in - bank.*|exchange.*|taler.*|backend.*|merchant.*|shop.*|libeufin.*|my.*|map.*|monnaie.*) + bank.*|exchange.*|taler.*|backend.*|merchant.*|shop.*|libeufin.*) rest="${d#*.}" if [[ "$rest" == *.* ]]; then d="$rest" @@ -178,50 +84,75 @@ apply_taler_domain() { d=$(_normalize_domain "$raw") TALER_DOMAIN="$d" - # 1) Explicit profile (domains.conf) — preferred way to add stacks - if load_domain_profile "$d" || load_domain_profile "$raw"; then - # Optional tiny defaults for e2e ladders by currency - case "${EXPECT_CURRENCY:-}" in - GOA) - : "${WITHDRAW_AMT:=GOA:20}" - : "${PAY_AMT:=GOA:0.01}" - : "${CREDIT_AMT:=GOA:400}" - ;; - KUDOS|TESTKUDOS) - MERCHANT_INSTANCE="${MERCHANT_INSTANCE:-sandbox}" - WITHDRAW_AMT="${WITHDRAW_AMT:-${EXPECT_CURRENCY}:20}" - PAY_AMT="${PAY_AMT:-${EXPECT_CURRENCY}:0.01}" - CREDIT_AMT="${CREDIT_AMT:-${EXPECT_CURRENCY}:100}" - ;; - CHF) - WITHDRAW_AMT="${WITHDRAW_AMT:-CHF:20}" - PAY_AMT="${PAY_AMT:-CHF:0.01}" - CREDIT_AMT="${CREDIT_AMT:-CHF:100}" - ;; - esac - else - # 2) Unknown domain — heuristics only (prefer profile in domains.conf) - # Override: --bank / --exchange / --merchant / --currency - # Do not keep default GOA: empty currency = report only, no hard fail. - BANK_PUBLIC="https://bank.${d}" - EXCHANGE_PUBLIC="https://exchange.${d}" - # TOPS-style multi-tenant merchant first, then legacy names - MERCHANT_PUBLIC="https://my.${d}" - EXPECT_CURRENCY="" - LOCAL_STACK=0 - SKIP_SSH=1 - CHECK_LANDING=0 - if [ "${TALER_DOMAIN_PROBE}" = "1" ]; then - local h - for h in "monnaie.${d}" "backend.${d}" "my.${d}" "taler.${d}" "merchant.${d}" "shop.${d}"; do - _probe_https_config "$h" && { MERCHANT_PUBLIC="https://$h"; break; } - done - for h in "bank.${d}" "libeufin.${d}"; do - _probe_https_config "$h" && { BANK_PUBLIC="https://$h"; break; } - done - _probe_https_config "exchange.${d}" || true - fi - fi + case "$d" in + # Local koopa stack only — SSH / inside / e2e allowed + koopa|hacktivism.ch|hacktivism) + BANK_PUBLIC="https://bank.hacktivism.ch" + EXCHANGE_PUBLIC="https://exchange.hacktivism.ch" + MERCHANT_PUBLIC="https://taler.hacktivism.ch" + EXPECT_CURRENCY="GOA" + LOCAL_STACK=1 + SKIP_SSH=0 + TALER_DOMAIN="hacktivism.ch" + : "${WITHDRAW_AMT:=GOA:20}" + : "${PAY_AMT:=GOA:0.01}" + : "${CREDIT_AMT:=GOA:400}" + ;; + taler.net|demo.taler.net) + # Official public demo (KUDOS) — public only, never SSH; tiny e2e amounts + BANK_PUBLIC="https://bank.demo.taler.net" + EXCHANGE_PUBLIC="https://exchange.demo.taler.net" + MERCHANT_PUBLIC="https://backend.demo.taler.net" + EXPECT_CURRENCY="KUDOS" + LOCAL_STACK=0 + SKIP_SSH=1 + MERCHANT_INSTANCE="${MERCHANT_INSTANCE:-sandbox}" + WITHDRAW_AMT="${WITHDRAW_AMT:-KUDOS:20}" + PAY_AMT="${PAY_AMT:-KUDOS:0.01}" + CREDIT_AMT="${CREDIT_AMT:-KUDOS:100}" + TALER_DOMAIN="demo.taler.net" + ;; + taler-ops.ch) + # Public CHF exchange; bank/merchant hosts vary — probe common names + EXCHANGE_PUBLIC="https://exchange.taler-ops.ch" + BANK_PUBLIC="https://bank.taler-ops.ch" + MERCHANT_PUBLIC="https://backend.taler-ops.ch" + EXPECT_CURRENCY="CHF" + LOCAL_STACK=0 + SKIP_SSH=1 + WITHDRAW_AMT="${WITHDRAW_AMT:-CHF:20}" + PAY_AMT="${PAY_AMT:-CHF:0.01}" + CREDIT_AMT="${CREDIT_AMT:-CHF:100}" + if [ "${TALER_DOMAIN_PROBE}" = "1" ]; then + local h + for h in bank.taler-ops.ch bank.demo.taler-ops.ch; do + _probe_https_config "$h" && { BANK_PUBLIC="https://$h"; break; } + done + for h in backend.taler-ops.ch merchant.taler-ops.ch taler.taler-ops.ch shop.taler-ops.ch; do + _probe_https_config "$h" && { MERCHANT_PUBLIC="https://$h"; break; } + done + fi + ;; + *) + # Any other domain — public HTTPS only, never SSH to koopa + BANK_PUBLIC="https://bank.${d}" + EXCHANGE_PUBLIC="https://exchange.${d}" + MERCHANT_PUBLIC="https://backend.${d}" + EXPECT_CURRENCY="${EXPECT_CURRENCY:-}" # unknown — don't hard-fail currency + LOCAL_STACK=0 + SKIP_SSH=1 + if [ "${TALER_DOMAIN_PROBE}" = "1" ]; then + local h + for h in "backend.${d}" "taler.${d}" "merchant.${d}" "shop.${d}"; do + _probe_https_config "$h" && { MERCHANT_PUBLIC="https://$h"; break; } + done + for h in "bank.${d}" "libeufin.${d}"; do + _probe_https_config "$h" && { BANK_PUBLIC="https://$h"; break; } + done + _probe_https_config "exchange.${d}" || true + fi + ;; + esac BANK_PUBLIC=${BANK_PUBLIC%/} EXCHANGE_PUBLIC=${EXCHANGE_PUBLIC%/} @@ -352,17 +283,10 @@ koopa_ssh_python() { with_timeout "$t" ssh "${SSH_BASE_OPTS[@]}" "${KOOPA_SSH}" python3 - } -# ANSI colours for tags (green OK / yellow WARN / red ERROR·BLOCKER / cyan INFO). -# Default: always on so pasted logs keep visible tags. Disable: NO_COLOR=1 or CLICOLOR=0. -if [ "${NO_COLOR:-0}" = "1" ] || [ "${CLICOLOR:-1}" = "0" ]; then +if [ "${NO_COLOR:-0}" = "1" ] || [ ! -t 1 ]; then G= R= Y= C= N= B= else - G=$'\e[1;32m' # bold green [OK] - R=$'\e[1;31m' # bold red [ERROR] [BLOCKER] - Y=$'\e[1;33m' # bold yellow [WARN] - C=$'\e[1;36m' # bold cyan [INFO] - B=$'\e[1m' - N=$'\e[0m' + G=$'\e[32m'; R=$'\e[31m'; Y=$'\e[33m'; C=$'\e[36m'; B=$'\e[1m'; N=$'\e[0m' fi PASS_N=0 @@ -667,35 +591,14 @@ read_secret() { } find_wallet_cli() { - # Must return a path suitable for: node "$WALLET_CLI" … - # Prefer *.mjs / bundled entry; plain /usr/bin/taler-wallet-cli is often a - # shell wrapper and cannot be passed to node. if [ -n "${WALLET_CLI:-}" ] && [ -f "$WALLET_CLI" ]; then echo "$WALLET_CLI"; return 0 fi - local c cand for c in \ - "${HOME}/.local/bin/taler-wallet-cli.mjs" \ - "${HOME}/taler/opt/taler-wallet-cli/usr/lib/taler-wallet-cli/node_modules/taler-wallet-cli/bin/taler-wallet-cli.mjs" \ - /home/hernani/taler/opt/taler-wallet-cli/usr/lib/taler-wallet-cli/node_modules/taler-wallet-cli/bin/taler-wallet-cli.mjs \ /Users/newkamek/src/taler/taler-typescript-core/packages/taler-wallet-cli/bin/taler-wallet-cli.mjs \ - /usr/lib/taler-wallet-cli/node_modules/taler-wallet-cli/bin/taler-wallet-cli.mjs \ - /usr/share/taler-wallet-cli/bin/taler-wallet-cli.mjs + "$(command -v taler-wallet-cli 2>/dev/null || true)" do [ -n "$c" ] && [ -f "$c" ] && { echo "$c"; return 0; } done - # Debian package wrapper → resolve real .mjs - cand=$(command -v taler-wallet-cli 2>/dev/null || true) - if [ -n "$cand" ] && [ -f "$cand" ]; then - if head -1 "$cand" 2>/dev/null | grep -q 'node\|mjs'; then - # shebang node script or .mjs - echo "$cand"; return 0 - fi - # follow symlink into package tree - if [ -L "$cand" ]; then - c=$(readlink -f "$cand" 2>/dev/null || true) - [ -n "$c" ] && [ -f "$c" ] && { echo "$c"; return 0; } - fi - fi return 1 } diff --git a/scripts/taler-monitoring/taler-monitoring.sh b/scripts/taler-monitoring/taler-monitoring.sh index 52d3d29..ff6586e 100755 --- a/scripts/taler-monitoring/taler-monitoring.sh +++ b/scripts/taler-monitoring/taler-monitoring.sh @@ -30,33 +30,26 @@ Phases: all urls + inside + versions + sanity + e2e (SSH phases only on koopa) Options: - -d, --domain DOMAIN load profile from domains.conf (bank/exchange/merchant) + -d, --domain DOMAIN target domain + koopa / hacktivism.ch → local stack, SSH ok + everything else → no SSH; e2e optional (tiny amounts) presets: koopa | hacktivism.ch | taler.net | taler-ops.ch - | my.taler-ops.ch | stage.taler-ops.ch - unknown domain → heuristic hosts (see README) - local (koopa) allows SSH; others public-only - --bank URL bank base (hostname or https://…) — overrides profile - --exchange URL exchange base — overrides profile - --merchant URL merchant-backend base — overrides profile + generic: bank/exchange/backend. + --bank URL override bank base (https://…) + --exchange URL override exchange base + --merchant URL override merchant base --currency CODE expected currency (GOA, KUDOS, CHF, …); empty = report only - --no-probe do not probe alternate hosts (unknown domains only) + --no-probe do not probe alternate merchant/bank hostnames -h, --help -Add a stack: edit domains.conf (name + bank + exchange + merchant + currency). - Examples: ./taler-monitoring.sh -d taler.net ./taler-monitoring.sh -d taler-ops.ch urls - ./taler-monitoring.sh -d my.taler-ops.ch urls - ./taler-monitoring.sh -d taler-ops.ch --merchant https://my.taler-ops.ch urls ./taler-monitoring.sh -d demo.taler.net --currency KUDOS - ./taler-monitoring.sh --exchange https://exchange.taler-ops.ch \ - --merchant https://my.taler-ops.ch --bank https://bank.taler-ops.ch urls + ./taler-monitoring.sh --exchange https://exchange.taler-ops.ch urls Env (same meaning): TALER_DOMAIN BANK_PUBLIC EXCHANGE_PUBLIC MERCHANT_PUBLIC EXPECT_CURRENCY - TALER_DOMAINS_CONF SKIP_SSH=1 - NO_COLOR=1 / CLICOLOR=0 disable green/yellow/red tags (default: coloured) SKIP_SSH=1 NO_COLOR=1 PERF_WARN_MS PERF_FAIL_MS (urls latency; default 8000 / 20000) KOOPA_SSH KOOPA_SSH_FALLBACKS (default koopa → koopa-external) @@ -140,11 +133,10 @@ fi # Export so check_*.sh (re-source lib) see the same targets via env export TALER_DOMAIN BANK_PUBLIC EXCHANGE_PUBLIC MERCHANT_PUBLIC -export EXPECT_CURRENCY SKIP_SSH LOCAL_STACK TALER_DOMAIN_PROBE CHECK_LANDING +export EXPECT_CURRENCY SKIP_SSH LOCAL_STACK TALER_DOMAIN_PROBE 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 -export PAIVANA_PUBLIC E2E_PAIVANA E2E_PAIVANA_TEMPLATE E2E_PAIVANA_AMOUNT E2E_PAIVANA_INSTANCE # 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}" diff --git a/scripts/taler-shared/upgrade-goa-debs.sh b/scripts/taler-shared/upgrade-goa-debs.sh deleted file mode 100755 index 0022510..0000000 --- a/scripts/taler-shared/upgrade-goa-debs.sh +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env bash -# Upgrade GNU Taler .deb packages *inside* the three GOA containers on koopa. -# Host openSUSE packages are unrelated (zypper) — do not confuse with this. -# -# Containers (no systemd as PID 1): after apt, restart with start_*.sh only. -# -# Run on koopa host as a user that can `podman exec` the containers: -# ./upgrade-goa-debs.sh -# ./upgrade-goa-debs.sh bank|exchange|merchant -# -# Mirror: scripts/taler-shared/ in koopa-admin-log. -# Live note: 2026/2026-07-16--taler-package-upgrade-goa.md -set -euo pipefail - -BANK_CTR="${BANK_CTR:-taler-hacktivism-bank}" -EXCHANGE_CTR="${EXCHANGE_CTR:-taler-hacktivism-exchange-ansible}" -MERCHANT_CTR="${MERCHANT_CTR:-taler-hacktivism}" - -only="${1:-all}" - -pod_root() { - local ctr="$1" - shift - podman exec -u root "$ctr" bash -c "$*" -} - -upgrade_bank() { - echo "======== bank ($BANK_CTR) ========" - pod_root "$BANK_CTR" ' - set -e - export DEBIAN_FRONTEND=noninteractive - apt-get update -qq - apt-get install -y libeufin-bank libeufin-common - dpkg -l libeufin-bank libeufin-common | awk "/^ii/{print \$2,\$3}" - ' - # restart app only (postgres via start_base if needed) - pod_root "$BANK_CTR" ' - set -e - if ! runuser -u postgres -- psql -c "SELECT 1" >/dev/null 2>&1; then - pg_ctlcluster 17 main start || true - sleep 2 - fi - mkdir -p /var/log/libeufin-bank - chown libeufin-bank:libeufin-bank /var/log/libeufin-bank 2>/dev/null || true - runuser -u libeufin-bank -- /usr/local/bin/start_bank.sh --restart - ' -} - -upgrade_exchange() { - echo "======== exchange ($EXCHANGE_CTR) ========" - pod_root "$EXCHANGE_CTR" ' - set -e - export DEBIAN_FRONTEND=noninteractive - apt-get update -qq - apt-get install -y \ - taler-exchange taler-exchange-database taler-exchange-offline \ - taler-exchange-typst libtalerexchange taler-terms-generator \ - taler-exchange-aml-webui taler-exchange-kyc-webui || true - dpkg -l "taler-exchange*" "libtalerexchange" "taler-terms-generator" 2>/dev/null \ - | awk "/^ii/{print \$2,\$3}" - ' - # do not run dbinit as root (role "root" does not exist) - pod_root "$EXCHANGE_CTR" ' - set -e - if id taler-exchange-httpd >/dev/null 2>&1; then - runuser -u taler-exchange-httpd -- taler-exchange-dbinit 2>&1 | tail -20 || true - fi - if [ -x /root/start_base_services_for_taler_exchange.sh ]; then - /root/start_base_services_for_taler_exchange.sh --no-shell 2>/dev/null || true - fi - if [ -x /usr/local/bin/start_exchange.sh ]; then - runuser -u taler-exchange-httpd -- /usr/local/bin/start_exchange.sh --restart 2>&1 | tail -30 || true - fi - pgrep -a taler-exchange-httpd | head -3 || true - ' -} - -upgrade_merchant() { - echo "======== merchant ($MERCHANT_CTR) ========" - pod_root "$MERCHANT_CTR" ' - set -e - export DEBIAN_FRONTEND=noninteractive - apt-get update -qq - apt-get install -y \ - taler-merchant taler-merchant-webui taler-merchant-typst \ - libtalermerchant taler-terms-generator - dpkg -l "taler-merchant*" "libtalermerchant" 2>/dev/null | awk "/^ii/{print \$2,\$3}" - ' - pod_root "$MERCHANT_CTR" ' - set -e - # schema: prefer tools as service user; failures may be noisy — check /config after - if id taler-merchant-httpd >/dev/null 2>&1; then - runuser -u taler-merchant-httpd -- taler-merchant-dbinit 2>&1 | tail -20 || true - fi - runuser -u taler-merchant-httpd -- /usr/local/bin/start_merchant.sh --restart - ' -} - -smoke() { - echo "======== smoke (host loopback) ========" - curl -sS -m 8 -o /dev/null -w "bank %{http_code} :9012/config\n" http://127.0.0.1:9012/config || true - curl -sS -m 8 -o /dev/null -w "exchange %{http_code} :9011/config\n" http://127.0.0.1:9011/config || true - curl -skS -m 8 -o /dev/null -w "merchant %{http_code} :9010/config\n" https://127.0.0.1:9010/config || true -} - -case "$only" in - all) - upgrade_bank - upgrade_exchange - upgrade_merchant - smoke - ;; - bank) upgrade_bank; smoke ;; - exchange) upgrade_exchange; smoke ;; - merchant) upgrade_merchant; smoke ;; - -h|--help|help) - sed -n '2,20p' "$0" - exit 0 - ;; - *) - echo "usage: $0 [all|bank|exchange|merchant]" >&2 - exit 2 - ;; -esac - -echo "DONE — re-run taler-monitoring versions/urls from a laptop if desired."