release 1.10.6: clean stage mon pages (no git noise, stage sticky, CHECK_BANK)
This commit is contained in:
parent
1d71766a64
commit
ef4dde4946
5 changed files with 135 additions and 50 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
1.10.5
|
||||
1.10.6
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ Git tags: `vMAJOR.FEATURE.FIX` (e.g. `v1.8.0`). File `VERSION` omits the `v` pre
|
|||
|
||||
| Tag | Date (UTC) | Notes |
|
||||
|-----|------------|--------|
|
||||
| **v1.10.6** | 2026-07-19 | **Fix:** stage mon HTML quality — suite update out of public log; filter git noise; stage-specific sticky (not GOA); `CHECK_BANK=0` / `MERCHANT_REQUIRED` for mytops stage scope. |
|
||||
| **v1.10.5** | 2026-07-19 | **Fix:** aptdeploy monpages **job-only** (own `/taler-monitoring-aptdeploy*`); full GOA mon inventory + bare URL checks stay on **hacktivism** general run — no bank/exchange/surface monpages noise on aptdeploy HTML. |
|
||||
| **v1.10.4** | 2026-07-19 | **Fix:** suite **auto-upgrade strict** (`SUITE_UPDATE_STRICT=1` default — abort on fetch fail); monpages ERROR on **bootstrap** HTML; ship mytops-stage timer/service units; host-agent refuses stale tree. |
|
||||
| **v1.10.3** | 2026-07-19 | **Bugfix:** sticky ERROR only from check badges (`┌ ERROR`) / `ERROR monpages`; ignore git `HEAD is now at …` commit subjects that mention ERROR. |
|
||||
|
|
|
|||
|
|
@ -303,14 +303,18 @@ check_perf() {
|
|||
esac
|
||||
}
|
||||
|
||||
# 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
|
||||
# Bank first (wallet-critical paths before UI chrome) — skip when CHECK_BANK=0 (e.g. mytops stage mon)
|
||||
if [ "${CHECK_BANK:-1}" = "1" ]; then
|
||||
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 /webui/" "$BANK_PUBLIC/webui/" 200,301,302
|
||||
else
|
||||
info "perf bank" "skipped (CHECK_BANK=0)"
|
||||
fi
|
||||
check_perf "perf bank /webui/" "$BANK_PUBLIC/webui/" 200,301,302
|
||||
|
||||
# Exchange
|
||||
check_perf "perf exchange /config" "$EXCHANGE_PUBLIC/config"
|
||||
|
|
@ -719,13 +723,17 @@ esac
|
|||
|
||||
# --- bank ---
|
||||
set_group bank
|
||||
if [ "${LOCAL_STACK:-1}" = "0" ]; then
|
||||
if [ "${CHECK_BANK:-1}" != "1" ]; then
|
||||
info "bank" "skipped (CHECK_BANK=0 — not in scope for this mon job)"
|
||||
code=""
|
||||
elif [ "${LOCAL_STACK:-1}" = "0" ]; then
|
||||
check_url_soft "bank /config" 200 "$BANK_PUBLIC/config"
|
||||
code=$(http_body "$BANK_PUBLIC/config" "$tmp/bc.json")
|
||||
else
|
||||
check_url "bank /config" 200 "$BANK_PUBLIC/config"
|
||||
code=$(http_body "$BANK_PUBLIC/config" "$tmp/bc.json")
|
||||
fi
|
||||
code=$(http_body "$BANK_PUBLIC/config" "$tmp/bc.json")
|
||||
if [ "$code" = "200" ]; then
|
||||
if [ "${CHECK_BANK:-1}" = "1" ] && [ "$code" = "200" ]; then
|
||||
expect_currency "bank" "$tmp/bc.json"
|
||||
if json_has_alt_unit_names "$tmp/bc.json" >/tmp/alt-bank.$$ 2>&1; then
|
||||
ok "bank /config alt_unit_names" "$(tr '\n' '; ' </tmp/alt-bank.$$ | sed 's/; $//')"
|
||||
|
|
@ -773,25 +781,28 @@ if [ "$code" = "200" ]; then
|
|||
fi
|
||||
|
||||
# Bank legal docs (landing nginx via Caddy /terms* /privacy* or /intro/*)
|
||||
check_legal_doc "bank /terms" "$BANK_PUBLIC/terms" "terms|GOA|exploration|bank|FADP|revDSG"
|
||||
# Prefer /privacy; fall back to /intro/privacy.html for older deploys
|
||||
code=$(http_code "$BANK_PUBLIC/privacy")
|
||||
if [ "$code" = "200" ]; then
|
||||
check_legal_doc "bank /privacy" "$BANK_PUBLIC/privacy" "privacy|FADP|revDSG|data|GOA|bank"
|
||||
else
|
||||
if [ "${LOCAL_STACK:-1}" = "1" ]; then
|
||||
check_legal_doc "bank /privacy (or /intro/privacy.html)" \
|
||||
"$BANK_PUBLIC/intro/privacy.html" "privacy|FADP|revDSG|data|GOA|bank"
|
||||
# still report bare /privacy failure for local
|
||||
warn "bank /privacy" "HTTP $code — prefer Caddy handle /privacy* → landing"
|
||||
if [ "${CHECK_BANK:-1}" = "1" ]; then
|
||||
check_legal_doc "bank /terms" "$BANK_PUBLIC/terms" "terms|GOA|exploration|bank|FADP|revDSG"
|
||||
# Prefer /privacy; fall back to /intro/privacy.html for older deploys
|
||||
code=$(http_code "$BANK_PUBLIC/privacy")
|
||||
if [ "$code" = "200" ]; then
|
||||
check_legal_doc "bank /privacy" "$BANK_PUBLIC/privacy" "privacy|FADP|revDSG|data|GOA|bank"
|
||||
else
|
||||
check_url_soft "bank /privacy" 200 "$BANK_PUBLIC/privacy"
|
||||
if [ "${LOCAL_STACK:-1}" = "1" ]; then
|
||||
check_legal_doc "bank /privacy (or /intro/privacy.html)" \
|
||||
"$BANK_PUBLIC/intro/privacy.html" "privacy|FADP|revDSG|data|GOA|bank"
|
||||
# still report bare /privacy failure for local
|
||||
warn "bank /privacy" "HTTP $code — prefer Caddy handle /privacy* → landing"
|
||||
else
|
||||
check_url_soft "bank /privacy" 200 "$BANK_PUBLIC/privacy"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- merchant ---
|
||||
set_group merchant
|
||||
if [ "${LOCAL_STACK:-1}" = "0" ]; then
|
||||
# MERCHANT_REQUIRED=1: hard ERROR if /config fails even when LOCAL_STACK=0 (mytops stage)
|
||||
if [ "${LOCAL_STACK:-1}" = "0" ] && [ "${MERCHANT_REQUIRED:-0}" != "1" ]; then
|
||||
check_url_soft "merchant /config" 200 "$MERCHANT_PUBLIC/config"
|
||||
else
|
||||
check_url "merchant /config" 200 "$MERCHANT_PUBLIC/config"
|
||||
|
|
|
|||
|
|
@ -145,7 +145,32 @@ mkdir -p "$LOG_DIR" "$HTML_BASE"
|
|||
|
||||
STAMP=$(date +%Y%m%d-%H%M%S)
|
||||
LOG="$LOG_DIR/run-${STAMP}.log"
|
||||
UPD_LOG="$LOG_DIR/suite-update-${STAMP}.log"
|
||||
: >"$LOG"
|
||||
|
||||
# --- suite auto-upgrade BEFORE the HTML log (git noise must not pollute mon pages) ---
|
||||
OVERLAY_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/taler-monitoring/suite-overlay"
|
||||
if [ -f "$AGENT_MON/taler-monitoring.sh" ]; then
|
||||
mkdir -p "$OVERLAY_DIR"
|
||||
rsync -a \
|
||||
--exclude secrets.env --exclude 'android-test/artifacts' --exclude 'android-test/apks' \
|
||||
--exclude 'android-test/out*' --exclude '__pycache__' \
|
||||
"$AGENT_MON/" "$OVERLAY_DIR/" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# shellcheck source=update-suite.sh
|
||||
if ! source "$AGENT_DIR/update-suite.sh" >"$UPD_LOG" 2>&1; then
|
||||
echo "ERROR: suite auto-update failed — refusing to run with stale tree" >&2
|
||||
echo " detail: $UPD_LOG" >&2
|
||||
tail -n 30 "$UPD_LOG" >&2 || true
|
||||
echo " fix git/network or set SUITE_UPDATE_STRICT=0 only as emergency" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ -d "${SUITE_DIR:-}/host-agent" ]; then
|
||||
AGENT_DIR="${SUITE_DIR}/host-agent"
|
||||
fi
|
||||
|
||||
# Now open the public HTML log (clean agent header + suite summary only)
|
||||
if command -v stdbuf >/dev/null 2>&1; then
|
||||
exec > >(stdbuf -oL -eL tee -a "$LOG") 2>&1
|
||||
else
|
||||
|
|
@ -157,30 +182,9 @@ echo "env_file=$ENV_FILE"
|
|||
echo "domain=$TALER_DOMAIN · phases=$PHASES · RUN_TIMEOUT=${RUN_TIMEOUT}s"
|
||||
echo "hosts=$MON_HOSTS"
|
||||
echo "flags INSIDE_PODMAN=${INSIDE_PODMAN:-} INSIDE_MODE=${INSIDE_MODE:-} LOCAL_STACK=${LOCAL_STACK:-} SKIP_SSH=${SKIP_SSH:-} INSIDE_PROFILE=${INSIDE_PROFILE:-}"
|
||||
|
||||
# --- refresh from Forgejo; re-apply suite-overlay if Forgejo lacks needed phases ---
|
||||
OVERLAY_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/taler-monitoring/suite-overlay"
|
||||
# preserve capable mon before reset wipes tracked files
|
||||
if [ -f "$AGENT_MON/taler-monitoring.sh" ]; then
|
||||
mkdir -p "$OVERLAY_DIR"
|
||||
rsync -a \
|
||||
--exclude secrets.env --exclude 'android-test/artifacts' --exclude 'android-test/apks' \
|
||||
--exclude 'android-test/out*' --exclude '__pycache__' \
|
||||
"$AGENT_MON/" "$OVERLAY_DIR/" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# shellcheck source=update-suite.sh
|
||||
# Strict suite auto-upgrade (default): abort if Forgejo fetch/reset fails so
|
||||
# hosts never keep publishing old / bootstrap HTML indefinitely.
|
||||
if ! source "$AGENT_DIR/update-suite.sh"; then
|
||||
echo "ERROR: suite auto-update failed — refusing to run with stale tree" >&2
|
||||
echo " fix git/network or set SUITE_UPDATE_STRICT=0 only as emergency" >&2
|
||||
exit 1
|
||||
fi
|
||||
# Prefer host-agent scripts from the *updated* suite tree
|
||||
if [ -d "${SUITE_DIR:-}/host-agent" ]; then
|
||||
AGENT_DIR="${SUITE_DIR}/host-agent"
|
||||
fi
|
||||
# One-line suite pin (no git M/checkout noise)
|
||||
echo "suite ${SUITE_VERSION:-?} @ ${COMMIT_SHORT:-?} ${COMMIT_URL:-}"
|
||||
echo " dir=${SUITE_DIR:-}"
|
||||
|
||||
SUITE_MON="${SUITE_DIR}"
|
||||
ROOT="$SUITE_MON"
|
||||
|
|
|
|||
|
|
@ -76,6 +76,13 @@ def ui(lang: str, key: str, **kwargs) -> str:
|
|||
"pages_i4": "Phase monpages: outside-in check (existence + top/bottom content markers; not merchant JSON code 21)",
|
||||
"pages_i5": "Host-agent: staging → DEPLOY_WWW_ROOT; reverse-proxy must serve /monitoring* and /taler-monitoring-surface*",
|
||||
"pages_i6": "This page host: {host} · path label: {label}",
|
||||
"stage_title": "mytops stage monitoring · {host}",
|
||||
"stage_summary": "betel only · CHF stage stack · not lifeline/prod · not GOA",
|
||||
"stage_i1": "Host: betel (stage). Public mon HTML: stage.my.taler-ops.ch + stage.taler-ops.ch /monitoring/",
|
||||
"stage_i2": "Focus: stage merchant ({host}) + exchange.stage.taler-ops.ch; bank optional (CHECK_BANK)",
|
||||
"stage_i3": "Phases: {phases} · suite auto-upgrade each timer run",
|
||||
"stage_i4": "Not GOA: no surface/aptdeploy/mail pages · no koopa-admin-log",
|
||||
"stage_i5": "Timer: taler-monitoring-mytops-stage.timer (4h) · user taler-monitoring",
|
||||
"pages_section_lead": "Monitoring pages themselves (suite):",
|
||||
"mm_title": "Mattermost chat health",
|
||||
"mm_summary": "mattermost.taler.net · SPA + /api/v4/system/ping · TLS",
|
||||
|
|
@ -150,6 +157,13 @@ def ui(lang: str, key: str, **kwargs) -> str:
|
|||
"pages_i3": "GOA : /monitoring/ bank+exchange+taler ; surface + aptdeploy sur taler.hacktivism.ch — mail/mattermost dans surface",
|
||||
"pages_i4": "Phase monpages : existence + marqueurs haut/bas (pas JSON merchant code 21)",
|
||||
"pages_i5": "Host-agent : staging → DEPLOY_WWW_ROOT ; le reverse-proxy sert /monitoring* et /taler-monitoring-surface*",
|
||||
"stage_title": "Surveillance mytops stage · {host}",
|
||||
"stage_summary": "betel uniquement · pile CHF stage · pas lifeline/prod · pas GOA",
|
||||
"stage_i1": "Hôte : betel (stage). HTML mon : stage.my.taler-ops.ch + stage.taler-ops.ch /monitoring/",
|
||||
"stage_i2": "Focus : merchant stage ({host}) + exchange.stage ; bank optionnel (CHECK_BANK)",
|
||||
"stage_i3": "Phases : {phases} · auto-upgrade suite à chaque minuterie",
|
||||
"stage_i4": "Pas GOA : pas de pages surface/aptdeploy/mail · pas de koopa-admin-log",
|
||||
"stage_i5": "Minuterie : taler-monitoring-mytops-stage.timer (4 h) · user taler-monitoring",
|
||||
"pages_i6": "Hôte de cette page : {host} · libellé : {label}",
|
||||
"pages_section_lead": "Les pages de monitoring elles-mêmes (suite) :",
|
||||
"mm_title": "Santé du chat Mattermost",
|
||||
|
|
@ -569,6 +583,24 @@ def monitoring_scope(
|
|||
}
|
||||
|
||||
phase_txt = phases or "urls · inside · versions"
|
||||
# mytops stage (betel) — not GOA sticky text
|
||||
if re.search(r"stage\.(my\.)?taler-ops\.ch|stage\.taler-ops\.ch|mytops-stage", host + " " + log_text, re.I):
|
||||
items = [
|
||||
ui(lang, "stage_i1"),
|
||||
ui(lang, "stage_i2", host=host),
|
||||
ui(lang, "stage_i3", phases=phase_txt),
|
||||
ui(lang, "stage_i4"),
|
||||
ui(lang, "stage_i5"),
|
||||
ui(lang, "pages_i6", host=host, label=label),
|
||||
]
|
||||
return {
|
||||
"kind": "stage",
|
||||
"lang": lang,
|
||||
"title": ui(lang, "stage_title", host=host),
|
||||
"summary": ui(lang, "stage_summary"),
|
||||
"items": items,
|
||||
}
|
||||
|
||||
role = "stack"
|
||||
if host.startswith("bank.") or "bank." in host:
|
||||
role = "bank"
|
||||
|
|
@ -602,6 +634,35 @@ def monitoring_scope(
|
|||
}
|
||||
|
||||
|
||||
def is_log_noise_line(ln: str) -> bool:
|
||||
"""Drop git/update chatter that must not appear in public mon HTML."""
|
||||
s = ln.strip()
|
||||
if not s:
|
||||
return False
|
||||
low = s.lower()
|
||||
if s.startswith("HEAD is now at"):
|
||||
return True
|
||||
if s.startswith("Your branch is") or s.startswith("branch '") or s.startswith('branch "'):
|
||||
return True
|
||||
if "set up to track" in low or "fast-forward" in low:
|
||||
return True
|
||||
if re.match(r"^M\t", s) or re.match(r"^M\s+\S", s):
|
||||
return True # git status "M path"
|
||||
if low.startswith("from https://") or low.startswith("from git@"):
|
||||
return True
|
||||
if "aktualisierung erzwungen" in low or "force update" in low:
|
||||
return True
|
||||
if low.startswith("fetch origin") or low.startswith("already at ") or low.startswith("upgraded "):
|
||||
# keep "suite vX @ commit" lines from agent header; drop raw fetch chatter
|
||||
if low.startswith("already at ") or low.startswith("upgraded "):
|
||||
return True
|
||||
if low.startswith("fetch origin"):
|
||||
return True
|
||||
if "ihr branch ist" in low or "bereits auf" in low:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def sticky_bar_html(
|
||||
*,
|
||||
generated_at: str,
|
||||
|
|
@ -972,7 +1033,11 @@ def build_html(
|
|||
suite_version: str = "",
|
||||
suite_version_url: str = "",
|
||||
) -> str:
|
||||
raw_lines = [strip_ansi(l).rstrip("\n") for l in log_text.splitlines()]
|
||||
raw_lines = [
|
||||
strip_ansi(l).rstrip("\n")
|
||||
for l in log_text.splitlines()
|
||||
if not is_log_noise_line(strip_ansi(l))
|
||||
]
|
||||
while raw_lines and not raw_lines[-1].strip():
|
||||
raw_lines.pop()
|
||||
|
||||
|
|
@ -1367,7 +1432,11 @@ def main() -> None:
|
|||
generated_at = now.strftime("%Y-%m-%d %H:%M:%SZ")
|
||||
title = args.title or f"{args.page_label} {args.mode} · {args.hostname}"
|
||||
|
||||
raw_for_counts = [strip_ansi(l).rstrip("\n") for l in log_text.splitlines()]
|
||||
raw_for_counts = [
|
||||
strip_ansi(l).rstrip("\n")
|
||||
for l in log_text.splitlines()
|
||||
if not is_log_noise_line(strip_ansi(l))
|
||||
]
|
||||
n_err, n_warn, _, _ = count_status(raw_for_counts)
|
||||
|
||||
if args.mode == "redirect":
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue