landing-stats: make collector multi-stack reusable
This commit is contained in:
parent
e1cc6d7141
commit
b6c3225e97
7 changed files with 291 additions and 58 deletions
|
|
@ -14,12 +14,14 @@ TimeoutStartSec=480
|
||||||
# Do not keep "active" after run — timer may fire again cleanly
|
# Do not keep "active" after run — timer may fire again cleanly
|
||||||
RemainAfterExit=no
|
RemainAfterExit=no
|
||||||
Environment=TZ=Europe/Zurich
|
Environment=TZ=Europe/Zurich
|
||||||
|
# Stack overrides (goa / stage-testpaysan / custom) — optional
|
||||||
|
EnvironmentFile=-%h/.config/taler-landing/stack.env
|
||||||
|
# GOA defaults if stack.env absent
|
||||||
Environment=ADMIN_LOG=%h/src/koopa/koopa-admin-log
|
Environment=ADMIN_LOG=%h/src/koopa/koopa-admin-log
|
||||||
Environment=SECRETS_BANK=%h/src/koopa/koopa-admin-secrets/koopa/host-root/taler-bank
|
Environment=SECRETS_BANK=%h/src/koopa/koopa-admin-secrets/koopa/host-root/taler-bank
|
||||||
Environment=BANK_URL=http://127.0.0.1:9012
|
Environment=BANK_URL=http://127.0.0.1:9012
|
||||||
Environment=BANK_PUBLIC_URL=https://bank.hacktivism.ch
|
Environment=BANK_PUBLIC_URL=https://bank.hacktivism.ch
|
||||||
Environment=EXCHANGE_CONFIG_URL=https://exchange.hacktivism.ch/config
|
Environment=EXCHANGE_CONFIG_URL=https://exchange.hacktivism.ch/config
|
||||||
# All accounts except exchange (double-count of withdraw credits on exchange ledger)
|
|
||||||
Environment=SCAN_SKIP=exchange
|
Environment=SCAN_SKIP=exchange
|
||||||
Environment=TX_PAGE=500
|
Environment=TX_PAGE=500
|
||||||
Environment=MAX_TX_PAGES=0
|
Environment=MAX_TX_PAGES=0
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,21 @@
|
||||||
# taler-landing — central stats (hernani user systemd)
|
# taler-landing — generic multi-stack landing stats
|
||||||
|
|
||||||
Public landing numbers on
|
One collector (`collect_bank_stats.py` + `collect-landing-stats.sh`) for any
|
||||||
|
currency / stack. **Defaults = GOA / hacktivism**; stage TESTPAYSAN uses a
|
||||||
|
profile file.
|
||||||
|
|
||||||
|
Public landing numbers (example GOA):
|
||||||
|
|
||||||
- https://bank.hacktivism.ch/intro/ → `stats.json`
|
- https://bank.hacktivism.ch/intro/ → `stats.json`
|
||||||
- https://exchange.hacktivism.ch/intro/ → `stats.json`
|
- https://exchange.hacktivism.ch/intro/ → `stats.json`
|
||||||
- https://taler.hacktivism.ch/intro/ → `stats.json`
|
- https://taler.hacktivism.ch/intro/ → `stats.json`
|
||||||
|
|
||||||
are produced by **one host process** as user **`hernani`**, not by three unrelated in-container crons.
|
Stage TESTPAYSAN (shared bank feed on all three hosts):
|
||||||
|
|
||||||
|
- https://stage.bank.lefrancpaysan.ch/intro/stats.json
|
||||||
|
(same file also under stage.exchange / stage.monnaie landings)
|
||||||
|
|
||||||
|
Produced by **one host process** (user systemd timer), not three crons.
|
||||||
|
|
||||||
## Why host / user systemd
|
## Why host / user systemd
|
||||||
|
|
||||||
|
|
@ -77,16 +86,37 @@ Preferred order:
|
||||||
|
|
||||||
Explorer password optional (shared-pool balance).
|
Explorer password optional (shared-pool balance).
|
||||||
|
|
||||||
|
## Profiles
|
||||||
|
|
||||||
|
| File | Stack |
|
||||||
|
|------|--------|
|
||||||
|
| `profiles/goa.env` | hacktivism GOA (container publish) |
|
||||||
|
| `profiles/stage-testpaysan.env` | FrancPaysan stage; **shared** host `stats.json` |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Stage (on stagepaysan):
|
||||||
|
STACK_PROFILE=stage-testpaysan ./scripts/taler-landing/install-landing-stats-host.sh
|
||||||
|
# or: francpaysan-admin-log/scripts/stagepaysan/install-landing-stats.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
`~/.config/taler-landing/stack.env` is sourced on each run.
|
||||||
|
|
||||||
## Env overrides
|
## Env overrides
|
||||||
|
|
||||||
| Env | Default | Meaning |
|
| Env | Default | Meaning |
|
||||||
|-----|---------|---------|
|
|-----|---------|---------|
|
||||||
| `BANK_URL` | `http://127.0.0.1:9012` | libeufin loopback |
|
| `BANK_URL` | `http://127.0.0.1:9012` | libeufin loopback |
|
||||||
|
| `BANK_CURRENCY` | *(auto)* | `GOA` / `TESTPAYSAN` / … |
|
||||||
| `SCAN_SKIP` | `exchange` | usernames excluded from flow |
|
| `SCAN_SKIP` | `exchange` | usernames excluded from flow |
|
||||||
|
| `COLLECT_BANK` / `_EXCHANGE` / `_MERCHANT` | `1` | phase switches |
|
||||||
|
| `COLLECT_RESOURCES` | `1` | container RSS/loadavg merge |
|
||||||
|
| `HOST_STATS_DIRS` | empty | space-separated host dirs for **shared** bank `stats.json` |
|
||||||
|
| `PUBLISH_PODMAN` | `1` | also `podman cp` into container landings |
|
||||||
| `TX_PAGE` | `500` | transactions page size |
|
| `TX_PAGE` | `500` | transactions page size |
|
||||||
| `MAX_TX_PAGES` | `0` | `0` = unlimited pages / account |
|
| `MAX_TX_PAGES` | `0` | `0` = unlimited pages / account |
|
||||||
| `ACCOUNTS_DELTA` | `-10000` | account list window |
|
| `ACCOUNTS_DELTA` | `-10000` | account list window |
|
||||||
| `ADMIN_LOG` | `%h/src/koopa/koopa-admin-log` | refresh in-container scripts |
|
| `ADMIN_LOG` | `%h/src/koopa/koopa-admin-log` | refresh in-container scripts |
|
||||||
|
| `STATS_SOURCE_LABEL` | `host collect_bank_stats.py` | `stats.source` field |
|
||||||
|
|
||||||
## UI alt names
|
## UI alt names
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Central landing-stats collector for hernani@koopa (user systemd timer).
|
# Generic landing-stats orchestrator (any Taler stack).
|
||||||
#
|
#
|
||||||
# - Bank: full account+ledger scan via collect_bank_stats.py → bank container
|
# Defaults = GOA / hacktivism on koopa. Override via env or EnvironmentFile
|
||||||
# - Exchange / merchant: existing in-container scripts, then amount_alt enrich
|
# (see profiles: goa | stage-testpaysan).
|
||||||
# - All three: container RSS / loadavg / top procs via mem-snapshot (podman exec)
|
#
|
||||||
# - Never wipes a good stats.json on failure (writes stats-run.json only)
|
# - Bank: collect_bank_stats.py (currency-agnostic) → stats.json
|
||||||
|
# - Optional: exchange / merchant in-container generators
|
||||||
|
# - Optional: container RSS/loadavg merge
|
||||||
|
# - Publish: podman into container landings and/or host dirs (shared bank stats)
|
||||||
|
# - Never wipes a good stats.json on failure (stats-run.json only)
|
||||||
#
|
#
|
||||||
# Install: scripts/taler-landing/install-landing-stats-host.sh
|
# Install: scripts/taler-landing/install-landing-stats-host.sh
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
@ -12,6 +16,20 @@ set -euo pipefail
|
||||||
export TZ="${TZ:-Europe/Zurich}"
|
export TZ="${TZ:-Europe/Zurich}"
|
||||||
export PATH="${HOME}/.local/bin:/usr/local/bin:/usr/bin:/bin${PATH:+:$PATH}"
|
export PATH="${HOME}/.local/bin:/usr/local/bin:/usr/bin:/bin${PATH:+:$PATH}"
|
||||||
|
|
||||||
|
# Optional stack profile: ~/.config/taler-landing/stack.env or STACK_ENV_FILE
|
||||||
|
if [ -n "${STACK_ENV_FILE:-}" ] && [ -f "${STACK_ENV_FILE}" ]; then
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
set -a
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
. "${STACK_ENV_FILE}"
|
||||||
|
set +a
|
||||||
|
elif [ -f "${HOME}/.config/taler-landing/stack.env" ]; then
|
||||||
|
set -a
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
. "${HOME}/.config/taler-landing/stack.env"
|
||||||
|
set +a
|
||||||
|
fi
|
||||||
|
|
||||||
log() { printf '%s %s\n' "$(date -Iseconds)" "$*"; }
|
log() { printf '%s %s\n' "$(date -Iseconds)" "$*"; }
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")" && pwd)"
|
ROOT="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
|
@ -22,6 +40,8 @@ elif [ -f "${HOME}/.local/lib/taler-landing/collect_bank_stats.py" ]; then
|
||||||
LIB="${HOME}/.local/lib/taler-landing"
|
LIB="${HOME}/.local/lib/taler-landing"
|
||||||
elif [ -f "${HOME}/src/koopa/koopa-admin-log/scripts/taler-landing/collect_bank_stats.py" ]; then
|
elif [ -f "${HOME}/src/koopa/koopa-admin-log/scripts/taler-landing/collect_bank_stats.py" ]; then
|
||||||
LIB="${HOME}/src/koopa/koopa-admin-log/scripts/taler-landing"
|
LIB="${HOME}/src/koopa/koopa-admin-log/scripts/taler-landing"
|
||||||
|
elif [ -f "${HOME}/taler/src/koopa-admin-log/scripts/taler-landing/collect_bank_stats.py" ]; then
|
||||||
|
LIB="${HOME}/taler/src/koopa-admin-log/scripts/taler-landing"
|
||||||
else
|
else
|
||||||
LIB="$ROOT"
|
LIB="$ROOT"
|
||||||
fi
|
fi
|
||||||
|
|
@ -29,6 +49,13 @@ fi
|
||||||
ADMIN_LOG="${ADMIN_LOG:-${HOME}/src/koopa/koopa-admin-log}"
|
ADMIN_LOG="${ADMIN_LOG:-${HOME}/src/koopa/koopa-admin-log}"
|
||||||
SECRETS_BANK="${SECRETS_BANK:-${HOME}/src/koopa/koopa-admin-secrets/koopa/host-root/taler-bank}"
|
SECRETS_BANK="${SECRETS_BANK:-${HOME}/src/koopa/koopa-admin-secrets/koopa/host-root/taler-bank}"
|
||||||
|
|
||||||
|
# Which phases to run (1/0)
|
||||||
|
COLLECT_BANK="${COLLECT_BANK:-1}"
|
||||||
|
COLLECT_EXCHANGE="${COLLECT_EXCHANGE:-1}"
|
||||||
|
COLLECT_MERCHANT="${COLLECT_MERCHANT:-1}"
|
||||||
|
COLLECT_RESOURCES="${COLLECT_RESOURCES:-1}"
|
||||||
|
|
||||||
|
# Containers (empty = skip podman publish for that role)
|
||||||
BANK_CTR="${BANK_CTR:-taler-hacktivism-bank}"
|
BANK_CTR="${BANK_CTR:-taler-hacktivism-bank}"
|
||||||
EX_CTR="${EX_CTR:-taler-hacktivism-exchange-ansible}"
|
EX_CTR="${EX_CTR:-taler-hacktivism-exchange-ansible}"
|
||||||
MER_CTR="${MER_CTR:-taler-hacktivism}"
|
MER_CTR="${MER_CTR:-taler-hacktivism}"
|
||||||
|
|
@ -36,10 +63,19 @@ MER_CTR="${MER_CTR:-taler-hacktivism}"
|
||||||
BANK_URL="${BANK_URL:-http://127.0.0.1:9012}"
|
BANK_URL="${BANK_URL:-http://127.0.0.1:9012}"
|
||||||
BANK_PUBLIC_URL="${BANK_PUBLIC_URL:-https://bank.hacktivism.ch}"
|
BANK_PUBLIC_URL="${BANK_PUBLIC_URL:-https://bank.hacktivism.ch}"
|
||||||
EXCHANGE_CONFIG_URL="${EXCHANGE_CONFIG_URL:-https://exchange.hacktivism.ch/config}"
|
EXCHANGE_CONFIG_URL="${EXCHANGE_CONFIG_URL:-https://exchange.hacktivism.ch/config}"
|
||||||
|
BANK_CURRENCY="${BANK_CURRENCY:-}" # empty → auto from bank/exchange /config
|
||||||
|
STATS_SOURCE_LABEL="${STATS_SOURCE_LABEL:-host collect_bank_stats.py}"
|
||||||
|
|
||||||
|
# In-container landing roots (podman publish)
|
||||||
BANK_LANDING_IN="${BANK_LANDING_IN:-/var/www/bank-landing}"
|
BANK_LANDING_IN="${BANK_LANDING_IN:-/var/www/bank-landing}"
|
||||||
EX_LANDING_IN="${EX_LANDING_IN:-/var/www/exchange-landing}"
|
EX_LANDING_IN="${EX_LANDING_IN:-/var/www/exchange-landing}"
|
||||||
MER_LANDING_IN="${MER_LANDING_IN:-/var/www/merchant-landing}"
|
MER_LANDING_IN="${MER_LANDING_IN:-/var/www/merchant-landing}"
|
||||||
|
PUBLISH_PODMAN="${PUBLISH_PODMAN:-1}"
|
||||||
|
|
||||||
|
# Host dirs that should get the *same* bank stats.json (shared public feed).
|
||||||
|
# Colon-separated (systemd EnvironmentFile-safe). Example stage:
|
||||||
|
# HOST_STATS_DIRS=/var/www/lfp-stage/bank:/var/www/lfp-stage/exchange:/var/www/lfp-stage/merchant
|
||||||
|
HOST_STATS_DIRS="${HOST_STATS_DIRS:-}"
|
||||||
|
|
||||||
WORKDIR="${LANDING_STATS_WORKDIR:-${XDG_RUNTIME_DIR:-/tmp}/taler-landing-stats}"
|
WORKDIR="${LANDING_STATS_WORKDIR:-${XDG_RUNTIME_DIR:-/tmp}/taler-landing-stats}"
|
||||||
mkdir -p "$WORKDIR"
|
mkdir -p "$WORKDIR"
|
||||||
|
|
@ -64,7 +100,9 @@ MEM_SRC="${MEM_SNAPSHOT_SRC:-$ADMIN_LOG/scripts/taler-shared/mem-snapshot.sh}"
|
||||||
|
|
||||||
merge_container_resources() {
|
merge_container_resources() {
|
||||||
local label="$1" ctr="$2" stats_file="$3"
|
local label="$1" ctr="$2" stats_file="$3"
|
||||||
|
[ "${COLLECT_RESOURCES}" = "1" ] || return 0
|
||||||
[ -f "$stats_file" ] || return 0
|
[ -f "$stats_file" ] || return 0
|
||||||
|
[ -n "$ctr" ] || return 0
|
||||||
if ! ctr_running "$ctr"; then
|
if ! ctr_running "$ctr"; then
|
||||||
log "WARN: $label resources: $ctr not running"
|
log "WARN: $label resources: $ctr not running"
|
||||||
return 1
|
return 1
|
||||||
|
|
@ -95,6 +133,36 @@ merge_container_resources() {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Write stats.json into host directories (shared feed: same file everywhere).
|
||||||
|
publish_host_stats() {
|
||||||
|
local src_stats="$1" src_run="${2:-}"
|
||||||
|
[ -n "${HOST_STATS_DIRS:-}" ] || return 0
|
||||||
|
[ -f "$src_stats" ] || return 0
|
||||||
|
local d paths
|
||||||
|
# Accept colon or space separators
|
||||||
|
paths=$(printf '%s' "$HOST_STATS_DIRS" | tr ': ' '\n' | sed '/^$/d')
|
||||||
|
while IFS= read -r d; do
|
||||||
|
[ -n "$d" ] || continue
|
||||||
|
if [ -d "$d" ] || mkdir -p "$d" 2>/dev/null; then
|
||||||
|
if cp -f "$src_stats" "${d}/stats.json" 2>/dev/null; then
|
||||||
|
chmod a+r "${d}/stats.json" 2>/dev/null || true
|
||||||
|
[ -n "$src_run" ] && [ -f "$src_run" ] && cp -f "$src_run" "${d}/stats-run.json" 2>/dev/null || true
|
||||||
|
log "host: published ${d}/stats.json"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if command -v sudo >/dev/null 2>&1 && sudo -n true 2>/dev/null; then
|
||||||
|
sudo mkdir -p "$d" 2>/dev/null || true
|
||||||
|
sudo cp -f "$src_stats" "${d}/stats.json"
|
||||||
|
sudo chmod a+r "${d}/stats.json" 2>/dev/null || true
|
||||||
|
[ -n "$src_run" ] && [ -f "$src_run" ] && sudo cp -f "$src_run" "${d}/stats-run.json" 2>/dev/null || true
|
||||||
|
log "host: published ${d}/stats.json (sudo)"
|
||||||
|
else
|
||||||
|
log "WARN: cannot write ${d}/stats.json (need write or passwordless sudo)"
|
||||||
|
fi
|
||||||
|
done <<<"$paths"
|
||||||
|
}
|
||||||
|
|
||||||
read_pass() {
|
read_pass() {
|
||||||
local name="$1" f
|
local name="$1" f
|
||||||
for f in \
|
for f in \
|
||||||
|
|
@ -107,12 +175,26 @@ read_pass() {
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
# container (hernani can podman exec root files inside owned containers)
|
# container secrets: /root/… (GOA) or /data/secrets/… (FrancPaysan stage)
|
||||||
if podman inspect -f '{{.State.Running}}' "$BANK_CTR" 2>/dev/null | grep -qx true; then
|
if [ -n "${BANK_CTR:-}" ] && podman inspect -f '{{.State.Running}}' "$BANK_CTR" 2>/dev/null | grep -qx true; then
|
||||||
if podman exec "$BANK_CTR" test -r "/root/${name}" 2>/dev/null; then
|
for path in "/root/${name}" "/data/secrets/${name}" "/data/secrets/bank-admin-password.txt"; do
|
||||||
podman exec "$BANK_CTR" cat "/root/${name}" 2>/dev/null | tr -d '\n'
|
case "$path" in
|
||||||
|
*bank-admin-password.txt)
|
||||||
|
[ "$name" = "bank-admin-password.txt" ] || continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
if podman exec "$BANK_CTR" test -r "$path" 2>/dev/null; then
|
||||||
|
podman exec "$BANK_CTR" cat "$path" 2>/dev/null | tr -d '\n\r'
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
done
|
||||||
|
# stage explorer secret naming
|
||||||
|
if [ "$name" = "bank-explorer-password.txt" ]; then
|
||||||
|
if podman exec "$BANK_CTR" test -r /data/secrets/bank-explorer-password.txt 2>/dev/null; then
|
||||||
|
podman exec "$BANK_CTR" cat /data/secrets/bank-explorer-password.txt 2>/dev/null | tr -d '\n\r'
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
@ -123,6 +205,8 @@ ctr_running() {
|
||||||
|
|
||||||
publish_json() {
|
publish_json() {
|
||||||
local ctr="$1" dest_dir="$2" src_stats="$3" src_run="$4"
|
local ctr="$1" dest_dir="$2" src_stats="$3" src_run="$4"
|
||||||
|
[ "${PUBLISH_PODMAN}" = "1" ] || return 0
|
||||||
|
[ -n "$ctr" ] || return 0
|
||||||
if ! ctr_running "$ctr"; then
|
if ! ctr_running "$ctr"; then
|
||||||
log "WARN: $ctr not running — skip publish $dest_dir"
|
log "WARN: $ctr not running — skip publish $dest_dir"
|
||||||
return 1
|
return 1
|
||||||
|
|
@ -166,6 +250,7 @@ collect_bank() {
|
||||||
BANK_URL="$BANK_URL" \
|
BANK_URL="$BANK_URL" \
|
||||||
BANK_PUBLIC_URL="$BANK_PUBLIC_URL" \
|
BANK_PUBLIC_URL="$BANK_PUBLIC_URL" \
|
||||||
EXCHANGE_CONFIG_URL="$EXCHANGE_CONFIG_URL" \
|
EXCHANGE_CONFIG_URL="$EXCHANGE_CONFIG_URL" \
|
||||||
|
BANK_CURRENCY="${BANK_CURRENCY:-}" \
|
||||||
BANK_ADMIN_PASS="$admin_pass" \
|
BANK_ADMIN_PASS="$admin_pass" \
|
||||||
BANK_EXPLORER_PASS="$explorer_pass" \
|
BANK_EXPLORER_PASS="$explorer_pass" \
|
||||||
DEMO_DIR="${demo_dir}" \
|
DEMO_DIR="${demo_dir}" \
|
||||||
|
|
@ -173,6 +258,7 @@ collect_bank() {
|
||||||
TX_PAGE="${TX_PAGE:-500}" \
|
TX_PAGE="${TX_PAGE:-500}" \
|
||||||
MAX_TX_PAGES="${MAX_TX_PAGES:-0}" \
|
MAX_TX_PAGES="${MAX_TX_PAGES:-0}" \
|
||||||
ACCOUNTS_DELTA="${ACCOUNTS_DELTA:--10000}" \
|
ACCOUNTS_DELTA="${ACCOUNTS_DELTA:--10000}" \
|
||||||
|
STATS_SOURCE_LABEL="$STATS_SOURCE_LABEL" \
|
||||||
"$PY" "$LIB/collect_bank_stats.py" \
|
"$PY" "$LIB/collect_bank_stats.py" \
|
||||||
--out "$WORKDIR/bank-stats.json" \
|
--out "$WORKDIR/bank-stats.json" \
|
||||||
--run-out "$WORKDIR/bank-stats-run.json" \
|
--run-out "$WORKDIR/bank-stats-run.json" \
|
||||||
|
|
@ -181,11 +267,13 @@ collect_bank() {
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
if [ "$ec_bank" -eq 0 ] && [ -f "$WORKDIR/bank-stats.json" ]; then
|
if [ "$ec_bank" -eq 0 ] && [ -f "$WORKDIR/bank-stats.json" ]; then
|
||||||
# Always attach in-container RSS/loadavg (not host /proc)
|
# Optional: attach in-container RSS/loadavg (not host /proc)
|
||||||
merge_container_resources bank "$BANK_CTR" "$WORKDIR/bank-stats.json" || true
|
merge_container_resources bank "$BANK_CTR" "$WORKDIR/bank-stats.json" || true
|
||||||
publish_json "$BANK_CTR" "$BANK_LANDING_IN" \
|
publish_json "$BANK_CTR" "$BANK_LANDING_IN" \
|
||||||
"$WORKDIR/bank-stats.json" "$WORKDIR/bank-stats-run.json"
|
"$WORKDIR/bank-stats.json" "$WORKDIR/bank-stats-run.json"
|
||||||
log "bank: OK → ${BANK_CTR}:${BANK_LANDING_IN}/stats.json"
|
# Shared public feed: same bank stats on all HOST_STATS_DIRS (bank/ex/merchant landings)
|
||||||
|
publish_host_stats "$WORKDIR/bank-stats.json" "$WORKDIR/bank-stats-run.json"
|
||||||
|
log "bank: OK (podman=${BANK_CTR:-none} host_dirs=${HOST_STATS_DIRS:-none})"
|
||||||
else
|
else
|
||||||
log "ERROR: bank collect failed (ec=$ec_bank) — previous stats.json kept"
|
log "ERROR: bank collect failed (ec=$ec_bank) — previous stats.json kept"
|
||||||
[ -f "$WORKDIR/bank-stats-run.json" ] || \
|
[ -f "$WORKDIR/bank-stats-run.json" ] || \
|
||||||
|
|
@ -272,13 +360,26 @@ collect_merchant() {
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
main() {
|
main() {
|
||||||
log "=== taler-landing-stats start (user=$(id -un) lib=$LIB) ==="
|
log "=== taler-landing-stats start (user=$(id -un) lib=$LIB currency=${BANK_CURRENCY:-auto}) ==="
|
||||||
|
log "phases bank=${COLLECT_BANK} exchange=${COLLECT_EXCHANGE} merchant=${COLLECT_MERCHANT} resources=${COLLECT_RESOURCES}"
|
||||||
|
if [ "${COLLECT_BANK}" = "1" ]; then
|
||||||
collect_bank || ec_bank=$?
|
collect_bank || ec_bank=$?
|
||||||
|
else
|
||||||
|
log "skip bank collect"
|
||||||
|
fi
|
||||||
|
if [ "${COLLECT_EXCHANGE}" = "1" ]; then
|
||||||
collect_exchange || ec_ex=$?
|
collect_exchange || ec_ex=$?
|
||||||
|
else
|
||||||
|
log "skip exchange collect"
|
||||||
|
fi
|
||||||
|
if [ "${COLLECT_MERCHANT}" = "1" ]; then
|
||||||
collect_merchant || ec_mer=$?
|
collect_merchant || ec_mer=$?
|
||||||
|
else
|
||||||
|
log "skip merchant collect"
|
||||||
|
fi
|
||||||
log "=== done bank=$ec_bank exchange=$ec_ex merchant=$ec_mer ==="
|
log "=== done bank=$ec_bank exchange=$ec_ex merchant=$ec_mer ==="
|
||||||
# non-zero if bank failed (primary public flow numbers); soft on ex/mer
|
# non-zero if bank failed (primary public flow numbers); soft on ex/mer
|
||||||
if [ "$ec_bank" -ne 0 ]; then
|
if [ "${COLLECT_BANK}" = "1" ] && [ "$ec_bank" -ne 0 ]; then
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,22 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""Full-scan bank landing stats (all accounts, all ledger money).
|
"""Full-scan bank landing stats (all accounts, all ledger money).
|
||||||
|
|
||||||
Run on koopa as hernani (or anywhere with admin API access). Writes stats.json
|
Generic for any currency stack (GOA, TESTPAYSAN, KUDOS, …). Run on the ops host
|
||||||
compatible with bank.hacktivism.ch/intro/ plus amount_alt fields for compact UI.
|
(with admin API access). Writes stats.json for public landings + amount_alt.
|
||||||
|
|
||||||
Env (selected):
|
Env (selected):
|
||||||
BANK_URL default http://127.0.0.1:9012
|
BANK_URL default http://127.0.0.1:9012
|
||||||
|
BANK_CURRENCY optional; else from exchange /config or first ledger amount
|
||||||
BANK_ADMIN_USER default admin
|
BANK_ADMIN_USER default admin
|
||||||
BANK_ADMIN_PASS or BANK_ADMIN_PASS_FILE / pass via --admin-pass-file
|
BANK_ADMIN_PASS or BANK_ADMIN_PASS_FILE / pass via --admin-pass-file
|
||||||
BANK_EXPLORER_USER default explorer
|
BANK_EXPLORER_USER default explorer
|
||||||
BANK_EXPLORER_PASS optional (balance_explorer)
|
BANK_EXPLORER_PASS optional (balance_explorer)
|
||||||
EXCHANGE_CONFIG_URL for alt_unit_names (default https://exchange.hacktivism.ch/config)
|
EXCHANGE_CONFIG_URL for alt_unit_names + currency
|
||||||
|
BANK_PUBLIC_URL public base for latency probes
|
||||||
OUT output path (default stdout if -)
|
OUT output path (default stdout if -)
|
||||||
SCAN_SKIP comma usernames excluded from flow (default: exchange)
|
SCAN_SKIP comma usernames excluded from flow (default: exchange)
|
||||||
TX_PAGE page size for transactions delta (default 500)
|
TX_PAGE / MAX_TX_PAGES / ACCOUNTS_DELTA / RECENT_WD_N / TZ
|
||||||
MAX_TX_PAGES 0 = unlimited pages per account (default 0)
|
STATS_SOURCE_LABEL optional string in stats.source field
|
||||||
ACCOUNTS_DELTA GET /accounts?delta= (default -10000)
|
|
||||||
RECENT_WD_N recent withdraws (default 10)
|
|
||||||
TZ default Europe/Zurich
|
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
@ -343,6 +342,11 @@ def main() -> int:
|
||||||
"--exchange-config",
|
"--exchange-config",
|
||||||
default=env("EXCHANGE_CONFIG_URL", "https://exchange.hacktivism.ch/config"),
|
default=env("EXCHANGE_CONFIG_URL", "https://exchange.hacktivism.ch/config"),
|
||||||
)
|
)
|
||||||
|
ap.add_argument(
|
||||||
|
"--currency",
|
||||||
|
default=env("BANK_CURRENCY", ""),
|
||||||
|
help="ledger currency code (optional; else exchange /config or first amount)",
|
||||||
|
)
|
||||||
ap.add_argument("--out", default=env("OUT", "-"))
|
ap.add_argument("--out", default=env("OUT", "-"))
|
||||||
ap.add_argument("--run-out", default=env("RUN_OUT", ""))
|
ap.add_argument("--run-out", default=env("RUN_OUT", ""))
|
||||||
ap.add_argument(
|
ap.add_argument(
|
||||||
|
|
@ -364,6 +368,11 @@ def main() -> int:
|
||||||
)
|
)
|
||||||
ap.add_argument("--recent", type=int, default=int(env("RECENT_WD_N", "10") or "10"))
|
ap.add_argument("--recent", type=int, default=int(env("RECENT_WD_N", "10") or "10"))
|
||||||
ap.add_argument("--public-base", default=env("BANK_PUBLIC_URL", "https://bank.hacktivism.ch"))
|
ap.add_argument("--public-base", default=env("BANK_PUBLIC_URL", "https://bank.hacktivism.ch"))
|
||||||
|
ap.add_argument(
|
||||||
|
"--source-label",
|
||||||
|
default=env("STATS_SOURCE_LABEL", "host collect_bank_stats.py"),
|
||||||
|
help="stats.source field (identify stack / collector)",
|
||||||
|
)
|
||||||
args = ap.parse_args()
|
args = ap.parse_args()
|
||||||
|
|
||||||
tz_name = env("TZ", "Europe/Zurich") or "Europe/Zurich"
|
tz_name = env("TZ", "Europe/Zurich") or "Europe/Zurich"
|
||||||
|
|
@ -378,6 +387,7 @@ def main() -> int:
|
||||||
|
|
||||||
bank = args.bank.rstrip("/")
|
bank = args.bank.rstrip("/")
|
||||||
skip = {s.strip() for s in (args.skip or "").split(",") if s.strip()}
|
skip = {s.strip() for s in (args.skip or "").split(",") if s.strip()}
|
||||||
|
currency_hint = (args.currency or "").strip().upper()
|
||||||
|
|
||||||
def write_run(ok: bool, err: Optional[str] = None) -> None:
|
def write_run(ok: bool, err: Optional[str] = None) -> None:
|
||||||
if not args.run_out:
|
if not args.run_out:
|
||||||
|
|
@ -397,6 +407,24 @@ def main() -> int:
|
||||||
raise RuntimeError("no admin password (BANK_ADMIN_PASS or --admin-pass-file)")
|
raise RuntimeError("no admin password (BANK_ADMIN_PASS or --admin-pass-file)")
|
||||||
token = get_token(bank, args.admin_user, admin_pass)
|
token = get_token(bank, args.admin_user, admin_pass)
|
||||||
alt = load_alt_from_config(args.exchange_config)
|
alt = load_alt_from_config(args.exchange_config)
|
||||||
|
# Currency: explicit → exchange /config → first ledger amount → GOA
|
||||||
|
currency = currency_hint
|
||||||
|
if not currency:
|
||||||
|
try:
|
||||||
|
code_c, cfg_d, _ = http_json(args.exchange_config, timeout=12)
|
||||||
|
if code_c == 200 and isinstance(cfg_d, dict) and cfg_d.get("currency"):
|
||||||
|
currency = str(cfg_d["currency"]).strip().upper()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if not currency:
|
||||||
|
try:
|
||||||
|
code_c, cfg_d, _ = http_json(f"{bank}/config", timeout=12)
|
||||||
|
if code_c == 200 and isinstance(cfg_d, dict) and cfg_d.get("currency"):
|
||||||
|
currency = str(cfg_d["currency"]).strip().upper()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if not currency:
|
||||||
|
currency = "GOA"
|
||||||
if not alt:
|
if not alt:
|
||||||
alt = dict(DEFAULT_ALT)
|
alt = dict(DEFAULT_ALT)
|
||||||
|
|
||||||
|
|
@ -442,13 +470,24 @@ def main() -> int:
|
||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
low = (subject or "").lower()
|
low = (subject or "").lower()
|
||||||
|
# Normalise bare numbers to stack currency
|
||||||
|
if ":" not in str(amount):
|
||||||
|
amount = f"{currency}:{amount}"
|
||||||
|
else:
|
||||||
|
# adopt ledger currency if we only had a hint
|
||||||
|
try:
|
||||||
|
cur0, _n0 = parse_amount(amount)
|
||||||
|
if cur0 and currency_hint == "" and cur0.upper() != "GOA":
|
||||||
|
currency = cur0.upper()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
if direction == "credit":
|
if direction == "credit":
|
||||||
total_in += n
|
total_in += n
|
||||||
n_incoming += 1
|
n_incoming += 1
|
||||||
incomings.append(
|
incomings.append(
|
||||||
{
|
{
|
||||||
"kind": "incoming",
|
"kind": "incoming",
|
||||||
"amount": amount if ":" in amount else f"GOA:{amount}",
|
"amount": amount,
|
||||||
"at_unix": ts,
|
"at_unix": ts,
|
||||||
"account": uname,
|
"account": uname,
|
||||||
"subject": subject,
|
"subject": subject,
|
||||||
|
|
@ -460,7 +499,7 @@ def main() -> int:
|
||||||
withdraws.append(
|
withdraws.append(
|
||||||
{
|
{
|
||||||
"kind": "withdraw",
|
"kind": "withdraw",
|
||||||
"amount": amount if ":" in amount else f"GOA:{amount}",
|
"amount": amount,
|
||||||
"at_unix": ts,
|
"at_unix": ts,
|
||||||
"account": uname,
|
"account": uname,
|
||||||
"subject": subject,
|
"subject": subject,
|
||||||
|
|
@ -503,7 +542,7 @@ def main() -> int:
|
||||||
users_n = sum(1 for u in accounts if u not in ("admin", "exchange"))
|
users_n = sum(1 for u in accounts if u not in ("admin", "exchange"))
|
||||||
|
|
||||||
def pack_amt(d: Decimal) -> Dict[str, Any]:
|
def pack_amt(d: Decimal) -> Dict[str, Any]:
|
||||||
f = format_amount_alt(f"GOA:{d}", alt)
|
f = format_amount_alt(f"{currency}:{d}", alt)
|
||||||
return {
|
return {
|
||||||
"amount": f["amount"],
|
"amount": f["amount"],
|
||||||
"amount_alt": f["amount_alt"],
|
"amount_alt": f["amount_alt"],
|
||||||
|
|
@ -567,10 +606,11 @@ def main() -> int:
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# explorer balance
|
# explorer / pool balance (shared demo account when present)
|
||||||
balance = "GOA:0"
|
zero = f"{currency}:0"
|
||||||
bal_alt = "GOA:0"
|
balance = zero
|
||||||
bal_full = "GOA:0"
|
bal_alt = zero
|
||||||
|
bal_full = zero
|
||||||
if explorer_pass:
|
if explorer_pass:
|
||||||
try:
|
try:
|
||||||
etok = get_token(bank, args.explorer_user, explorer_pass)
|
etok = get_token(bank, args.explorer_user, explorer_pass)
|
||||||
|
|
@ -583,7 +623,7 @@ def main() -> int:
|
||||||
balance = str(
|
balance = str(
|
||||||
data.get("balance", {}).get("amount")
|
data.get("balance", {}).get("amount")
|
||||||
if isinstance(data.get("balance"), dict)
|
if isinstance(data.get("balance"), dict)
|
||||||
else data.get("amount") or data.get("balance") or "GOA:0"
|
else data.get("amount") or data.get("balance") or zero
|
||||||
)
|
)
|
||||||
# sometimes balance is object with amount
|
# sometimes balance is object with amount
|
||||||
if isinstance(data.get("balance"), dict) and data["balance"].get(
|
if isinstance(data.get("balance"), dict) and data["balance"].get(
|
||||||
|
|
@ -608,7 +648,7 @@ def main() -> int:
|
||||||
)
|
)
|
||||||
if code == 200 and isinstance(data, dict):
|
if code == 200 and isinstance(data, dict):
|
||||||
if isinstance(data.get("balance"), dict):
|
if isinstance(data.get("balance"), dict):
|
||||||
balance = str(data["balance"].get("amount") or "GOA:0")
|
balance = str(data["balance"].get("amount") or zero)
|
||||||
elif data.get("amount"):
|
elif data.get("amount"):
|
||||||
balance = str(data["amount"])
|
balance = str(data["amount"])
|
||||||
bf = format_amount_alt(balance, alt)
|
bf = format_amount_alt(balance, alt)
|
||||||
|
|
@ -637,12 +677,12 @@ def main() -> int:
|
||||||
|
|
||||||
stats = {
|
stats = {
|
||||||
"ok": True,
|
"ok": True,
|
||||||
"currency": "GOA",
|
"currency": currency,
|
||||||
"timezone": tz_name,
|
"timezone": tz_name,
|
||||||
"generated_at": gen_iso,
|
"generated_at": gen_iso,
|
||||||
"generated_at_human": gen_human,
|
"generated_at_human": gen_human,
|
||||||
"generated_at_unix": now_u,
|
"generated_at_unix": now_u,
|
||||||
"source": "host collect_bank_stats.py (hernani systemd)",
|
"source": str(args.source_label or "host collect_bank_stats.py"),
|
||||||
"bank_url": bank,
|
"bank_url": bank,
|
||||||
"scan": {
|
"scan": {
|
||||||
"tx_page": args.tx_page,
|
"tx_page": args.tx_page,
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,41 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Install central landing-stats collector as hernani user systemd timer.
|
# Install generic landing-stats collector as user systemd timer.
|
||||||
#
|
#
|
||||||
# On koopa:
|
# GOA / koopa (default):
|
||||||
# cd ~/src/koopa/koopa-admin-log
|
# cd ~/src/koopa/koopa-admin-log
|
||||||
# ./scripts/taler-landing/install-landing-stats-host.sh
|
# ./scripts/taler-landing/install-landing-stats-host.sh
|
||||||
# systemctl --user start taler-landing-stats.service # one-shot now
|
|
||||||
# systemctl --user status taler-landing-stats.timer
|
|
||||||
#
|
#
|
||||||
# Requires: linger enabled for hernani (loginctl enable-linger hernani)
|
# Stage TESTPAYSAN (stagepaysan on francpaysan host):
|
||||||
# so the timer runs without an interactive login.
|
# STACK_PROFILE=stage-testpaysan ./scripts/taler-landing/install-landing-stats-host.sh
|
||||||
|
# # or from francpaysan-admin-log: ./scripts/stagepaysan/install-landing-stats.sh
|
||||||
|
#
|
||||||
|
# Optional: STACK_ENV_FILE=/path/to/profile.env
|
||||||
|
# Requires linger: sudo loginctl enable-linger $USER
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||||
ADMIN_LOG="${ADMIN_LOG:-$ROOT}"
|
ADMIN_LOG="${ADMIN_LOG:-$ROOT}"
|
||||||
SRC="$ADMIN_LOG/scripts/taler-landing"
|
SRC="$ADMIN_LOG/scripts/taler-landing"
|
||||||
UNIT_SRC="$ADMIN_LOG/configs/systemd/user"
|
UNIT_SRC="$ADMIN_LOG/configs/systemd/user"
|
||||||
|
PROFILE="${STACK_PROFILE:-goa}"
|
||||||
|
|
||||||
BIN_DST="${HOME}/.local/bin"
|
BIN_DST="${HOME}/.local/bin"
|
||||||
LIB_DST="${HOME}/.local/lib/taler-landing"
|
LIB_DST="${HOME}/.local/lib/taler-landing"
|
||||||
UNIT_DST="${HOME}/.config/systemd/user"
|
UNIT_DST="${HOME}/.config/systemd/user"
|
||||||
STATE_DST="${HOME}/.local/state/taler-landing-stats"
|
STATE_DST="${HOME}/.local/state/taler-landing-stats"
|
||||||
|
CFG_DST="${HOME}/.config/taler-landing"
|
||||||
|
|
||||||
mkdir -p "$BIN_DST" "$LIB_DST" "$UNIT_DST" "$STATE_DST"
|
mkdir -p "$BIN_DST" "$LIB_DST" "$UNIT_DST" "$STATE_DST" "$CFG_DST"
|
||||||
|
|
||||||
install -m 0755 "$SRC/collect-landing-stats.sh" "$BIN_DST/collect-landing-stats.sh"
|
install -m 0755 "$SRC/collect-landing-stats.sh" "$BIN_DST/collect-landing-stats.sh"
|
||||||
install -m 0755 "$SRC/collect_bank_stats.py" "$LIB_DST/collect_bank_stats.py"
|
install -m 0755 "$SRC/collect_bank_stats.py" "$LIB_DST/collect_bank_stats.py"
|
||||||
install -m 0755 "$SRC/enrich_stats_alt.py" "$LIB_DST/enrich_stats_alt.py"
|
install -m 0755 "$SRC/enrich_stats_alt.py" "$LIB_DST/enrich_stats_alt.py"
|
||||||
install -m 0755 "$SRC/merge_resources.py" "$LIB_DST/merge_resources.py"
|
install -m 0755 "$SRC/merge_resources.py" "$LIB_DST/merge_resources.py"
|
||||||
install -m 0755 "$SRC/collect_container_resources.sh" "$LIB_DST/collect_container_resources.sh"
|
install -m 0755 "$SRC/collect_container_resources.sh" "$LIB_DST/collect_container_resources.sh"
|
||||||
install -m 0755 "$SRC/test-landing-stats.sh" "$BIN_DST/test-landing-stats.sh" 2>/dev/null || \
|
if [ -f "$SRC/test-landing-stats.sh" ]; then
|
||||||
|
install -m 0755 "$SRC/test-landing-stats.sh" "$BIN_DST/test-landing-stats.sh" 2>/dev/null || \
|
||||||
install -m 0755 "$SRC/test-landing-stats.sh" "$LIB_DST/test-landing-stats.sh"
|
install -m 0755 "$SRC/test-landing-stats.sh" "$LIB_DST/test-landing-stats.sh"
|
||||||
|
fi
|
||||||
install -m 0644 "$SRC/goa_amounts.py" "$LIB_DST/goa_amounts.py"
|
install -m 0644 "$SRC/goa_amounts.py" "$LIB_DST/goa_amounts.py"
|
||||||
# mem-snapshot helper lives in taler-shared (copied into containers at collect time)
|
# mem-snapshot helper lives in taler-shared (copied into containers at collect time)
|
||||||
if [ -f "$ADMIN_LOG/scripts/taler-shared/mem-snapshot.sh" ]; then
|
if [ -f "$ADMIN_LOG/scripts/taler-shared/mem-snapshot.sh" ]; then
|
||||||
|
|
@ -37,18 +43,34 @@ if [ -f "$ADMIN_LOG/scripts/taler-shared/mem-snapshot.sh" ]; then
|
||||||
"$LIB_DST/mem-snapshot.sh"
|
"$LIB_DST/mem-snapshot.sh"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Wrapper always uses installed lib next to itself when LIB discovery works;
|
# Stack profile → ~/.config/taler-landing/stack.env (sourced by collector)
|
||||||
# also point ADMIN_LOG for in-container script refresh.
|
if [ -n "${STACK_ENV_FILE:-}" ] && [ -f "${STACK_ENV_FILE}" ]; then
|
||||||
|
install -m 0644 "${STACK_ENV_FILE}" "$CFG_DST/stack.env"
|
||||||
|
elif [ -f "$SRC/profiles/${PROFILE}.env" ]; then
|
||||||
|
install -m 0644 "$SRC/profiles/${PROFILE}.env" "$CFG_DST/stack.env"
|
||||||
|
else
|
||||||
|
echo "WARN: no profile ${PROFILE}.env — collector uses built-in GOA defaults" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
install -m 0644 "$UNIT_SRC/taler-landing-stats.service" "$UNIT_DST/"
|
install -m 0644 "$UNIT_SRC/taler-landing-stats.service" "$UNIT_DST/"
|
||||||
install -m 0644 "$UNIT_SRC/taler-landing-stats.timer" "$UNIT_DST/"
|
install -m 0644 "$UNIT_SRC/taler-landing-stats.timer" "$UNIT_DST/"
|
||||||
|
|
||||||
# Rewrite ExecStart to installed binary if unit uses %h path — units already do.
|
# Point unit EnvironmentFile at stack profile
|
||||||
|
if grep -q '^EnvironmentFile=' "$UNIT_DST/taler-landing-stats.service" 2>/dev/null; then
|
||||||
|
:
|
||||||
|
else
|
||||||
|
# inject after [Service]
|
||||||
|
sed -i '/^\[Service\]/a EnvironmentFile=-%h/.config/taler-landing/stack.env' \
|
||||||
|
"$UNIT_DST/taler-landing-stats.service"
|
||||||
|
fi
|
||||||
|
|
||||||
systemctl --user daemon-reload
|
systemctl --user daemon-reload
|
||||||
systemctl --user enable --now taler-landing-stats.timer
|
systemctl --user enable --now taler-landing-stats.timer
|
||||||
|
|
||||||
echo "Installed (user=$(id -un)):"
|
echo "Installed (user=$(id -un) profile=${PROFILE}):"
|
||||||
echo " $BIN_DST/collect-landing-stats.sh"
|
echo " $BIN_DST/collect-landing-stats.sh"
|
||||||
echo " $LIB_DST/{collect_bank_stats,enrich_stats_alt,goa_amounts}.py"
|
echo " $LIB_DST/{collect_bank_stats,enrich_stats_alt,goa_amounts}.py"
|
||||||
|
echo " $CFG_DST/stack.env"
|
||||||
echo " $UNIT_DST/taler-landing-stats.{service,timer} (timer enabled)"
|
echo " $UNIT_DST/taler-landing-stats.{service,timer} (timer enabled)"
|
||||||
echo " logs: $STATE_DST/"
|
echo " logs: $STATE_DST/"
|
||||||
echo
|
echo
|
||||||
|
|
@ -61,8 +83,6 @@ echo "Run once now:"
|
||||||
echo " systemctl --user start taler-landing-stats.service"
|
echo " systemctl --user start taler-landing-stats.service"
|
||||||
echo " journalctl --user -u taler-landing-stats.service -n 40 --no-pager"
|
echo " journalctl --user -u taler-landing-stats.service -n 40 --no-pager"
|
||||||
echo
|
echo
|
||||||
echo "Optional secrets (if not readable via podman exec bank /root/…):"
|
echo "Secrets (if not via podman exec bank):"
|
||||||
echo " mkdir -p ~/.config/taler-landing"
|
echo " mkdir -p ~/.config/taler-landing && chmod 700 ~/.config/taler-landing"
|
||||||
echo " cp …/bank-admin-password.txt ~/.config/taler-landing/"
|
echo " # bank-admin-password.txt bank-explorer-password.txt"
|
||||||
echo " cp …/bank-explorer-password.txt ~/.config/taler-landing/"
|
|
||||||
echo " chmod 600 ~/.config/taler-landing/*"
|
|
||||||
|
|
|
||||||
18
scripts/taler-landing/profiles/goa.env
Normal file
18
scripts/taler-landing/profiles/goa.env
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Stack profile: GOA / hacktivism
|
||||||
|
# systemd EnvironmentFile: KEY=value only (no export)
|
||||||
|
BANK_CTR=taler-hacktivism-bank
|
||||||
|
EX_CTR=taler-hacktivism-exchange-ansible
|
||||||
|
MER_CTR=taler-hacktivism
|
||||||
|
BANK_URL=http://127.0.0.1:9012
|
||||||
|
BANK_PUBLIC_URL=https://bank.hacktivism.ch
|
||||||
|
EXCHANGE_CONFIG_URL=https://exchange.hacktivism.ch/config
|
||||||
|
BANK_CURRENCY=GOA
|
||||||
|
BANK_LANDING_IN=/var/www/bank-landing
|
||||||
|
EX_LANDING_IN=/var/www/exchange-landing
|
||||||
|
MER_LANDING_IN=/var/www/merchant-landing
|
||||||
|
COLLECT_BANK=1
|
||||||
|
COLLECT_EXCHANGE=1
|
||||||
|
COLLECT_MERCHANT=1
|
||||||
|
COLLECT_RESOURCES=1
|
||||||
|
PUBLISH_PODMAN=1
|
||||||
|
STATS_SOURCE_LABEL="host collect_bank_stats.py goa hacktivism"
|
||||||
22
scripts/taler-landing/profiles/stage-testpaysan.env
Normal file
22
scripts/taler-landing/profiles/stage-testpaysan.env
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Stack profile: FrancPaysan stage / TESTPAYSAN (ops user stagepaysan)
|
||||||
|
# systemd EnvironmentFile: KEY=value only (no export, no shell expansion)
|
||||||
|
BANK_CTR=stage-lfp-bank
|
||||||
|
EX_CTR=stage-lfp-exchange-ansible
|
||||||
|
MER_CTR=stage-lfp-merchant
|
||||||
|
BANK_URL=http://127.0.0.1:9032
|
||||||
|
BANK_PUBLIC_URL=https://stage.bank.lefrancpaysan.ch
|
||||||
|
EXCHANGE_CONFIG_URL=https://stage.exchange.lefrancpaysan.ch/config
|
||||||
|
BANK_CURRENCY=TESTPAYSAN
|
||||||
|
SCAN_SKIP=exchange
|
||||||
|
BANK_LANDING_IN=/data/var/www
|
||||||
|
EX_LANDING_IN=/data/var/www
|
||||||
|
MER_LANDING_IN=/data/var/www
|
||||||
|
# Shared public feed: one bank scan → same stats.json on all three Caddy landings
|
||||||
|
# Colon-separated for systemd EnvironmentFile
|
||||||
|
HOST_STATS_DIRS=/var/www/lfp-stage/bank:/var/www/lfp-stage/exchange:/var/www/lfp-stage/merchant
|
||||||
|
COLLECT_BANK=1
|
||||||
|
COLLECT_EXCHANGE=0
|
||||||
|
COLLECT_MERCHANT=0
|
||||||
|
COLLECT_RESOURCES=0
|
||||||
|
PUBLISH_PODMAN=1
|
||||||
|
STATS_SOURCE_LABEL="host collect_bank_stats.py stage TESTPAYSAN shared"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue