taler-monitoring/host-agent/ensure-apt-deploy-test-containers.sh
Hernâni Marques 0c94fb3d2e
release 1.13.6: env-only machine paths and SSH hosts
Load ~/.config/taler-monitoring/env (taler-monitoring-env profiles)
before suite defaults. Drop hardcoded operator homes and host aliases
from scripts; apply/staging/www/secrets/wallet via env.
2026-07-19 03:33:12 +02:00

368 lines
13 KiB
Bash
Executable file

#!/usr/bin/env bash
# ensure-apt-deploy-test-containers.sh
#
# Four rootless podman containers on koopa (no nginx / no HTTPS):
#
# Fresh rebuild when repo fingerprint changes:
# koopa-taler-deploy-test-apt-src-trixie
# koopa-taler-deploy-test-apt-src-trixie-testing
#
# Persistent upgrade path (mytops upgrade.sh style):
# koopa-taler-deploy-test-apt-src-trixie-upgrade
# koopa-taler-deploy-test-apt-src-trixie-testing-upgrade
#
# Run as hernani on koopa. From elsewhere use run-aptdeploy.sh (ssh $DEPLOY_SSH or $APT_DEPLOY_SSH).
#
set -euo pipefail
PODMAN_BIN="${APT_DEPLOY_PODMAN:-podman}"
IMG="${APT_DEPLOY_BASE_IMAGE:-docker.io/library/debian:trixie}"
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/taler-apt-deploy"
URI_BASE="${APT_DEPLOY_URI:-https://deb.taler.net/apt/debian}"
mkdir -p "$STATE_DIR"
# Packages we track for "new version → rebuild fresh containers"
TRACK_PKGS="${APT_DEPLOY_TRACK_PKGS:-taler-merchant libtalermerchant libtalerexchange libdonau}"
# Canonical four containers (keep). Everything else matching legacy names is removed.
CANONICAL_CONTAINERS=(
koopa-taler-deploy-test-apt-src-trixie
koopa-taler-deploy-test-apt-src-trixie-testing
koopa-taler-deploy-test-apt-src-trixie-upgrade
koopa-taler-deploy-test-apt-src-trixie-testing-upgrade
)
# Legacy / typo names from earlier iterations — always delete if present
LEGACY_CONTAINERS=(
koopa-taler-build-test-apt-trixie
koopa-taler-build-test-apt-trixie-testing
koopa-taler-deploy-test-apt-trixie
koopa-taler-deploy-test-apt-trixie-testing
koopa-taler-buidl-test-apt-trixie
koopa-taler-buidl-test-apt-trixie-testing
)
cleanup_legacy() {
local n img
echo "======== cleanup legacy containers / images ========"
for n in "${LEGACY_CONTAINERS[@]}"; do
if "$PODMAN_BIN" container exists "$n" 2>/dev/null; then
echo "remove legacy container $n"
"$PODMAN_BIN" rm -f "$n" 2>/dev/null || true
fi
# old setup images for that name
if "$PODMAN_BIN" image exists "localhost/${n}:setup" 2>/dev/null; then
echo "remove legacy image localhost/${n}:setup"
"$PODMAN_BIN" rmi -f "localhost/${n}:setup" 2>/dev/null || true
fi
done
# dangling setup images not in canonical set
while read -r img; do
[ -n "$img" ] || continue
local base keep=0
base=${img#localhost/}
base=${base%:setup}
for n in "${CANONICAL_CONTAINERS[@]}"; do
[ "$base" = "$n" ] && keep=1 && break
done
if [ "$keep" -eq 0 ] && [[ "$img" == localhost/koopa-taler-*-test-apt* ]]; then
echo "remove non-canonical image $img"
"$PODMAN_BIN" rmi -f "$img" 2>/dev/null || true
fi
done < <("$PODMAN_BIN" images --format '{{.Repository}}:{{.Tag}}' 2>/dev/null | grep -E 'localhost/koopa-taler-.*-test-apt' || true)
}
# Prefer single suite tree: ~/src/taler-monitoring vs ~/taler-monitoring
# (legacy koopa-admin-log paths are not used). Keep the newer git clone; symlink the other.
dedupe_suite_repos() {
local a="$HOME/src/taler-monitoring" b="$HOME/taler-monitoring"
local ta tb
[ "${APT_DEPLOY_DEDUPE_REPOS:-1}" = "1" ] || return 0
if [ -d "$a/.git" ] && [ -d "$b/.git" ] && [ ! -L "$a" ] && [ ! -L "$b" ] \
&& [ "$(readlink -f "$a" 2>/dev/null || echo "$a")" != "$(readlink -f "$b" 2>/dev/null || echo "$b")" ]; then
ta=$(git -C "$a" log -1 --format=%ct 2>/dev/null || echo 0)
tb=$(git -C "$b" log -1 --format=%ct 2>/dev/null || echo 0)
echo "======== dedupe suite repos (both are git clones) ========"
echo " $a HEAD_ts=$ta"
echo " $b HEAD_ts=$tb"
if [ "$ta" -ge "$tb" ]; then
echo "keep $a · remove $b · symlink $b$a"
rm -rf "$b"
ln -sfn "$a" "$b"
else
echo "keep $b · remove $a · symlink $a$b"
rm -rf "$a"
mkdir -p "$(dirname "$a")"
ln -sfn "$b" "$a"
fi
elif [ -d "$a/.git" ] && [ ! -e "$b" ]; then
ln -sfn "$a" "$b"
elif [ -d "$b/.git" ] && [ ! -e "$a" ]; then
mkdir -p "$(dirname "$a")"
ln -sfn "$b" "$a"
fi
}
cleanup_legacy
dedupe_suite_repos
# ---------------------------------------------------------------------------
# Repo fingerprint: Version: lines from suite Packages index
# ---------------------------------------------------------------------------
repo_pkg_version() {
local suite=$1 pkg=$2
curl -fsS --max-time 45 \
"${URI_BASE}/dists/${suite}/main/binary-amd64/Packages" 2>/dev/null \
| awk -v p="$pkg" '
$0 == "Package: " p { want=1; next }
/^Package: / { want=0 }
want && /^Version: / { print $2; exit }
'
}
repo_fingerprint() {
local suite=$1 pkg v line=""
for pkg in $TRACK_PKGS; do
v=$(repo_pkg_version "$suite" "$pkg" || true)
[ -n "$v" ] || v="?"
line="${line}${pkg}=${v};"
done
printf '%s' "$line"
}
container_fingerprint() {
local name=$1
"$PODMAN_BIN" exec "$name" bash -lc '
for p in '"$TRACK_PKGS"'; do
v=$(dpkg-query -W -f="\${Version}" "$p" 2>/dev/null || echo missing)
printf "%s=%s;" "$p" "$v"
done
' 2>/dev/null || echo "missing"
}
# ---------------------------------------------------------------------------
# Bootstrap: install base + taler source + packages (shared)
# ---------------------------------------------------------------------------
install_base_and_merchant() {
local name=$1 suite=$2 srcfile=$3
"$PODMAN_BIN" exec -u root "$name" bash -lc '
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y -qq ca-certificates curl wget gnupg systemd systemd-sysv \
dbus procps iproute2
'
"$PODMAN_BIN" exec -u root "$name" bash -lc "
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
mkdir -p /etc/apt/keyrings
wget -q -O /etc/apt/keyrings/taler-systems.gpg https://taler.net/taler-systems.gpg
cat >/etc/apt/sources.list.d/${srcfile} <<EOF
Architectures: amd64
Components: main
X-Repolib-Name: Taler
Signed-By: /etc/apt/keyrings/taler-systems.gpg
Suites: ${suite}
Types: deb
URIs: ${URI_BASE}
EOF
apt-get update -qq
apt-get install -y \
taler-merchant \
taler-merchant-typst \
taler-merchant-webui \
taler-terms-generator \
postgresql \
s-nail \
jq
"
}
commit_and_systemd() {
local name=$1
"$PODMAN_BIN" stop "$name"
"$PODMAN_BIN" commit "$name" "localhost/${name}:setup"
"$PODMAN_BIN" rm "$name"
"$PODMAN_BIN" run -d --name "$name" \
--hostname "$name" \
--systemd=always \
--cgroupns=host \
"localhost/${name}:setup" \
/lib/systemd/systemd
sleep 5
# enable merchant stack if unit exists
"$PODMAN_BIN" exec "$name" bash -lc '
set +e
systemctl daemon-reload 2>/dev/null
systemctl enable taler-merchant.target 2>/dev/null
systemctl start taler-merchant.target 2>/dev/null
sleep 2
systemctl is-active taler-merchant-httpd.service 2>/dev/null || true
' || true
}
create_from_scratch() {
local name=$1 suite=$2 srcfile=$3
echo "======== CREATE (fresh) $name Suites: $suite ========"
"$PODMAN_BIN" pull "$IMG" >/dev/null
"$PODMAN_BIN" rm -f "$name" 2>/dev/null || true
# drop previous setup image so we do not accumulate duplicates
"$PODMAN_BIN" rmi -f "localhost/${name}:setup" 2>/dev/null || true
"$PODMAN_BIN" run -d --name "$name" --hostname "$name" "$IMG" sleep infinity
install_base_and_merchant "$name" "$suite" "$srcfile"
commit_and_systemd "$name"
printf '%s\n' "$(repo_fingerprint "$suite")" >"$STATE_DIR/${name}.fp"
printf '%s\n' "$(container_fingerprint "$name")" >"$STATE_DIR/${name}.installed"
echo "created $name fp=$(cat "$STATE_DIR/${name}.fp")"
}
# ---------------------------------------------------------------------------
# Upgrade path (mytops-admin-log upgrade.sh merchant packages, no restic/nginx)
# Prints a markdown-ish table of before → after versions.
# ---------------------------------------------------------------------------
upgrade_inside() {
local name=$1
local before after pkg v0 v1
echo "======== UPGRADE $name (mytops-style apt install + upgrade) ========"
before=$("$PODMAN_BIN" exec "$name" bash -lc '
for p in taler-merchant libtalermerchant libtalerexchange libdonau libgnunet \
taler-merchant-webui taler-merchant-typst taler-terms-generator; do
v=$(dpkg-query -W -f="\${Version}" "$p" 2>/dev/null || echo "-")
printf "%s %s\n" "$p" "$v"
done
' 2>/dev/null || true)
# capture upgrade output
set +e
"$PODMAN_BIN" exec -u root "$name" bash -lc '
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
systemctl stop taler-merchant.target 2>/dev/null || true
systemctl stop taler-merchant-donaukeyupdate.service 2>/dev/null || true
apt-get update -qq
apt-get install -y \
taler-merchant \
taler-merchant-typst \
taler-merchant-webui \
taler-terms-generator \
|| true
if dpkg -l challenger-httpd 2>/dev/null | grep -q "^ii"; then
apt-get remove -y challenger-httpd || true
fi
apt-get upgrade -y
systemctl daemon-reload 2>/dev/null || true
systemctl enable taler-merchant.target 2>/dev/null || true
# try dbconfig if present (may no-op without full config)
command -v taler-merchant-dbconfig >/dev/null && taler-merchant-dbconfig 2>/dev/null || true
systemctl reset-failed "taler-merchant*" 2>/dev/null || true
systemctl start taler-merchant.target 2>/dev/null || true
sleep 2
' 2>&1 | tee "$STATE_DIR/${name}.upgrade.log" | tail -30
set -e
after=$("$PODMAN_BIN" exec "$name" bash -lc '
for p in taler-merchant libtalermerchant libtalerexchange libdonau libgnunet \
taler-merchant-webui taler-merchant-typst taler-terms-generator; do
v=$(dpkg-query -W -f="\${Version}" "$p" 2>/dev/null || echo "-")
printf "%s %s\n" "$p" "$v"
done
' 2>/dev/null || true)
echo
echo "| package | before | after | change |"
echo "|---------|--------|-------|--------|"
while read -r pkg v0; do
[ -n "${pkg:-}" ] || continue
v1=$(printf '%s\n' "$after" | awk -v p="$pkg" '$1==p {print $2; exit}')
v1=${v1:--}
if [ "$v0" = "$v1" ]; then
ch="="
else
ch="UPGRADED"
fi
echo "| $pkg | $v0 | $v1 | $ch |"
done <<<"$before"
printf '%s\n' "$(container_fingerprint "$name")" >"$STATE_DIR/${name}.installed"
}
# ---------------------------------------------------------------------------
# Fresh mode: recreate if missing / not running / repo fp changed
# ---------------------------------------------------------------------------
ensure_fresh() {
local name=$1 suite=$2 srcfile=$3
local want have running
want=$(repo_fingerprint "$suite")
echo "repo fingerprint [$suite]: $want"
if ! "$PODMAN_BIN" container exists "$name" 2>/dev/null; then
create_from_scratch "$name" "$suite" "$srcfile"
return
fi
running=$("$PODMAN_BIN" inspect -f '{{.State.Running}}' "$name" 2>/dev/null || echo false)
have=$(container_fingerprint "$name")
echo "installed in $name: $have"
if [ "$running" != "true" ] \
|| ! "$PODMAN_BIN" exec "$name" bash -lc 'command -v taler-merchant-httpd' >/dev/null 2>&1 \
|| [ "$want" != "$have" ]; then
echo "rebuild $name (running=$running fp_match=$([ "$want" = "$have" ] && echo yes || echo NO))"
create_from_scratch "$name" "$suite" "$srcfile"
else
echo "OK $name up-to-date (fresh container matches repo)"
fi
}
# ---------------------------------------------------------------------------
# Upgrade mode: create once, then always upgrade_inside
# ---------------------------------------------------------------------------
ensure_upgrade() {
local name=$1 suite=$2 srcfile=$3
local running
if ! "$PODMAN_BIN" container exists "$name" 2>/dev/null; then
create_from_scratch "$name" "$suite" "$srcfile"
echo "(initial install for upgrade-track container $name)"
return
fi
running=$("$PODMAN_BIN" inspect -f '{{.State.Running}}' "$name" 2>/dev/null || echo false)
if [ "$running" != "true" ]; then
echo "start $name"
"$PODMAN_BIN" start "$name" || {
echo "recreate broken $name"
create_from_scratch "$name" "$suite" "$srcfile"
return
}
sleep 3
fi
if ! "$PODMAN_BIN" exec "$name" bash -lc 'command -v taler-merchant-httpd' >/dev/null 2>&1; then
echo "recreate $name (no httpd after start)"
create_from_scratch "$name" "$suite" "$srcfile"
return
fi
upgrade_inside "$name"
}
MODE="${1:-all}" # all | fresh | upgrade
case "$MODE" in
all|fresh)
ensure_fresh koopa-taler-deploy-test-apt-src-trixie trixie taler.sources
ensure_fresh koopa-taler-deploy-test-apt-src-trixie-testing trixie-testing taler-testing.sources
;;&
all|upgrade)
ensure_upgrade koopa-taler-deploy-test-apt-src-trixie-upgrade trixie taler.sources
ensure_upgrade koopa-taler-deploy-test-apt-src-trixie-testing-upgrade trixie-testing taler-testing.sources
;;
*)
echo "usage: $0 [all|fresh|upgrade]" >&2
exit 2
;;
esac
echo "done ensure-apt-deploy-test-containers mode=$MODE"