#!/usr/bin/env bash # verify-install-pgpool-ii-ubuntu.sh # # Verifies every claim in install-pgpool-ii-ubuntu.html that is checkable from # this machine. Pgpool-II itself CANNOT be installed here (macOS, no Linux host, # no container runtime), so nothing below pretends to exercise a live cluster. # The documentation claims are verified by fetching the official pgpool.net # pages and asserting the quoted text is actually present on them. # # Run: bash verify-install-pgpool-ii-ubuntu.sh # Exit: 0 if every checkable claim PASSes, 1 otherwise. # Network-dependent checks report SKIP (not FAIL) when offline. set -u WORK="$(mktemp -d "${TMPDIR:-/tmp}/verify-pgpool.XXXXXX")" trap 'rm -rf "$WORK"' EXIT PASS=0; FAIL=0; SKIP=0 ok() { printf 'PASS %s\n' "$1"; PASS=$((PASS+1)); } bad() { printf 'FAIL %s\n' "$1"; FAIL=$((FAIL+1)); } skip() { printf 'SKIP %s\n' "$1"; SKIP=$((SKIP+1)); } check(){ if [ "$2" = "$3" ]; then ok "$1"; else bad "$1 (expected [$3], got [$2])"; fi; } # Fetch $1 into $2, stripping tags into plain text. Returns 1 on network failure. fetch_text() { curl -sL --max-time 30 -A 'Mozilla/5.0' -o "$WORK/raw" -w '%{http_code}' "$1" > "$WORK/code" 2>/dev/null || return 1 [ -s "$WORK/raw" ] || return 1 python3 - "$WORK/raw" "$2" <<'PY' import re, html, sys t = open(sys.argv[1], encoding='utf-8', errors='replace').read() t = re.sub(r'(?s)<(script|style).*?', ' ', t) t = re.sub(r'<[^>]+>', ' ', t) t = re.sub(r'\s+', ' ', html.unescape(t)) open(sys.argv[2], 'w', encoding='utf-8').write(t) PY } has() { grep -qF "$2" "$1"; } ONLINE=1 curl -sL --max-time 15 -o /dev/null https://www.pgpool.net/ 2>/dev/null || ONLINE=0 [ "$ONLINE" -eq 1 ] || printf 'NOTE: pgpool.net unreachable; network checks will SKIP.\n\n' printf '== A. The pgpoolAdmin download from the old article ==\n' if [ "$ONLINE" -eq 1 ]; then URL='http://www.pgpool.net/download.php?f=pgpoolAdmin-3.10.1.tar.gz' CODE=$(curl -sL --max-time 30 -o "$WORK/dl.bin" -w '%{http_code}' "$URL" 2>/dev/null) SIZE=$(wc -c < "$WORK/dl.bin" | tr -d ' ') check "A1 old article's download URL returns HTTP 404" "$CODE" "404" if [ "$SIZE" -gt 0 ] && head -c 512 "$WORK/dl.bin" | grep -qi ' /dev/null 2> "$WORK/tar.err"; TRC=$? check "A3 'tar -xf' on the downloaded file fails (nonzero exit)" \ "$([ "$TRC" -ne 0 ] && echo nonzero || echo zero)" "nonzero" printf ' tar said: %s\n' "$(cat "$WORK/tar.err")" else skip "A1-A3 download URL checks (offline)" fi printf '\n== B. The pgpoolAdmin source repository ==\n' if [ "$ONLINE" -eq 1 ]; then curl -sL --max-time 30 -o "$WORK/repo.json" \ https://api.github.com/repos/pgpool/pgpooladmin 2>/dev/null PUSHED=$(grep -o '"pushed_at": *"[^"]*"' "$WORK/repo.json" | head -1 | sed 's/.*"\([0-9-]*\)T.*/\1/') check "B1 repository last pushed 2021-06-17" "$PUSHED" "2021-06-17" curl -sL --max-time 30 -o "$WORK/tags.json" \ 'https://api.github.com/repos/pgpool/pgpooladmin/tags?per_page=100' 2>/dev/null if grep -q '"name": *"V4_2_0"' "$WORK/tags.json"; then ok "B2 highest release tag V4_2_0 is present" else bad "B2 tag V4_2_0 not found" fi if grep -q '"name": *"V4_3' "$WORK/tags.json"; then bad "B3 a 4.3+ tag exists -- the article's claim would be wrong" else ok "B3 no 4.3-or-later tag exists (no build for supported Pgpool-II)" fi if grep -q '"name": *"V3_10' "$WORK/tags.json"; then bad "B4 a 3.10 tag exists -- 'never existed' claim would be wrong" else ok "B4 no 3.10 tag exists (pgpoolAdmin-3.10.1 was never a release)" fi else skip "B1-B4 repository checks (offline)" fi printf '\n== C. pgpoolAdmin is absent from the current pgpool.net downloads page ==\n' if [ "$ONLINE" -eq 1 ] && fetch_text 'https://www.pgpool.net/mediawiki/index.php/Downloads' "$WORK/dl.txt"; then N=$(grep -ci 'pgpooladmin' "$WORK/dl.txt" || true) check "C1 downloads page mentions pgpoolAdmin zero times" "$N" "0" else skip "C1 downloads page check (offline or fetch failed)" fi printf '\n== D. Configuration claims, against the official documentation ==\n' DOC=https://www.pgpool.net/docs/latest/en/html if [ "$ONLINE" -eq 1 ] && fetch_text "$DOC/configuring-pcp-conf.html" "$WORK/pcp.txt"; then if has "$WORK/pcp.txt" 'All operation modes require the pcp.conf file to be set'; then ok "D1 docs say: 'All operation modes require the pcp.conf file to be set.'" else bad "D1 quoted pcp.conf sentence not found in the docs" fi else skip "D1 pcp.conf doc check" fi if [ "$ONLINE" -eq 1 ] && fetch_text "$DOC/runtime-config-health-check.html" "$WORK/hc.txt"; then if has "$WORK/hc.txt" 'Default is 0, which means health check is disabled'; then ok "D2 docs say health_check_period defaults to 0 = disabled" else bad "D2 quoted health_check_period sentence not found" fi else skip "D2 health check doc check" fi if [ "$ONLINE" -eq 1 ] && fetch_text "$DOC/runtime-config-connection.html" "$WORK/conn.txt"; then if has "$WORK/conn.txt" 'The port number used by Pgpool-II to listen for connections. Default is 9999'; then ok "D3 docs say port defaults to 9999" else bad "D3 quoted port default not found" fi if has "$WORK/conn.txt" 'The default value is localhost'; then ok "D4 docs say listen_addresses defaults to localhost" else bad "D4 quoted listen_addresses default not found" fi else skip "D3-D4 connection doc checks" fi if [ "$ONLINE" -eq 1 ] && fetch_text "$DOC/runtime-streaming-replication-check.html" "$WORK/sr.txt"; then if has "$WORK/sr.txt" 'for the identification of the primary server'; then ok "D5 docs confirm sr_check_* identify the primary server" else bad "D5 quoted sr_check sentence not found" fi else skip "D5 sr_check doc check" fi if [ "$ONLINE" -eq 1 ] && fetch_text "$DOC/auth-methods.html" "$WORK/auth.txt"; then if has "$WORK/auth.txt" 'SCRAM authentication is supported using the pool_passwd authentication file'; then ok "D6 docs confirm SCRAM requires pool_passwd" else bad "D6 quoted SCRAM/pool_passwd sentence not found" fi if has "$WORK/auth.txt" "md5 type user passwords in pool_passwd file can't be used for scram authentication"; then ok "D7 docs confirm md5 pool_passwd entries are unusable for SCRAM" else bad "D7 quoted md5/SCRAM caveat not found" fi else skip "D6-D7 auth doc checks" fi printf '\n== E. load_balance_mode default changed between 4.2 and 4.3 ==\n' if [ "$ONLINE" -eq 1 ] \ && fetch_text 'https://www.pgpool.net/docs/42/en/html/runtime-config-load-balancing.html' "$WORK/lb42.txt" \ && fetch_text 'https://www.pgpool.net/docs/43/en/html/runtime-config-load-balancing.html' "$WORK/lb43.txt"; then V42=$(sed 's/.*load_balance_mode ( boolean )//' "$WORK/lb42.txt" | grep -o 'Default is o[nf]*' | head -1) V43=$(sed 's/.*load_balance_mode ( boolean )//' "$WORK/lb43.txt" | grep -o 'Default is o[nf]*' | head -1) check "E1 4.2 docs: load_balance_mode default off" "$V42" "Default is off" check "E2 4.3 docs: load_balance_mode default on" "$V43" "Default is on" else skip "E1-E2 load_balance_mode version comparison" fi printf '\n== F. PostgreSQL default password encryption (local, live) ==\n' export PATH="/opt/homebrew/opt/postgresql@17/bin:$PATH" if command -v psql > /dev/null 2>&1 \ && psql -h 127.0.0.1 -p 55432 -U postgres -Atc 'select 1' > /dev/null 2>&1; then BOOT=$(psql -h 127.0.0.1 -p 55432 -U postgres -Atc \ "select boot_val from pg_settings where name='password_encryption'" 2>/dev/null) check "F1 PostgreSQL compiled-in password_encryption default is scram-sha-256" \ "$BOOT" "scram-sha-256" psql -h 127.0.0.1 -p 55432 -U postgres -Atc 'select version()' 2>/dev/null \ | sed 's/^/ /' else skip "F1 local PostgreSQL not reachable on 127.0.0.1:55432" fi printf '\n== G. Not verifiable on this hardware ==\n' printf 'SKIP G1 apt install pgpool2 (no Linux host, no container runtime)\n' printf 'SKIP G2 live failover / health check (requires a running cluster)\n' printf 'SKIP G3 pcp_node_info / SHOW POOL_NODES against a real Pgpool-II\n' printf 'SKIP G4 journalctl -u pgpool2 (no systemd on macOS)\n' SKIP=$((SKIP+4)) printf '\n== %d passed, %d failed, %d skipped ==\n' "$PASS" "$FAIL" "$SKIP" [ "$FAIL" -eq 0 ] || exit 1 exit 0