#!/bin/bash # Shared utility functions for Archipelago scripts # # Source this from any script: # source "$(dirname "$0")/lib/common.sh" # # Provides: logging, SSH helpers, health checks, disk checks, memory limits # Guard against double-sourcing [ -n "${_ARCHY_COMMON_LOADED:-}" ] && return 0 _ARCHY_COMMON_LOADED=1 # ── Colored logging ───────────────────────────────────────────────────── log_info() { echo -e "\033[0;32m[INFO]\033[0m $(date '+%H:%M:%S') $*"; } log_warn() { echo -e "\033[0;33m[WARN]\033[0m $(date '+%H:%M:%S') $*"; } log_error() { echo -e "\033[0;31m[ERROR]\033[0m $(date '+%H:%M:%S') $*"; } # ── SSH wrapper with deploy key ───────────────────────────────────────── # Usage: ssh_cmd # Uses the standard deploy key and safe defaults. ssh_cmd() { local host="$1"; shift local key="${ARCHIPELAGO_SSH_KEY:-$HOME/.ssh/archipelago-deploy}" ssh -i "$key" \ -o StrictHostKeyChecking=no \ -o ConnectTimeout=10 \ -o ServerAliveInterval=15 \ -o ServerAliveCountMax=4 \ "archipelago@${host}" "$@" } # Usage: scp_cmd # Wraps scp with the same deploy key and options. scp_cmd() { local key="${ARCHIPELAGO_SSH_KEY:-$HOME/.ssh/archipelago-deploy}" scp -i "$key" \ -o StrictHostKeyChecking=no \ -o ConnectTimeout=10 \ "$@" } # ── Health check ──────────────────────────────────────────────────────── # Wait for an HTTP health endpoint to respond successfully. # Usage: wait_for_health [max_wait_seconds] [path] wait_for_health() { local host="$1" max_wait="${2:-60}" path="${3:-/health}" local waited=0 while [ $waited -lt $max_wait ]; do if curl -sf "http://${host}${path}" >/dev/null 2>&1; then log_info "Health check passed for ${host}" return 0 fi sleep 2 waited=$((waited + 2)) done log_error "Health check failed for ${host} after ${max_wait}s" return 1 } # ── Disk space check ─────────────────────────────────────────────────── # Check that disk usage on a remote host is below a threshold. # Usage: check_disk_space [max_percent] check_disk_space() { local host="$1" max_pct="${2:-85}" local pct pct=$(ssh_cmd "$host" "df / | tail -1 | awk '{print \$(NF-1)}' | tr -d '%'" 2>/dev/null) if [ -n "$pct" ] && [ "$pct" -gt "$max_pct" ] 2>/dev/null; then log_error "Disk at ${pct}% on ${host} (max ${max_pct}%)" return 1 fi return 0 } # ── Memory limit calculator ──────────────────────────────────────────── # Returns the memory limit for a container by name. # Checks /etc/archipelago/memory-limits.conf first (override), then falls # back to built-in defaults. Mirrors the pattern in first-boot-containers.sh. # # Low-memory mode: set LOW_MEM=true before calling to get reduced limits # on certain heavy containers. # # Usage: mem_limit mem_limit() { local name="$1" # Allow per-host overrides via config file local limit limit=$(grep "^${name}=" /etc/archipelago/memory-limits.conf 2>/dev/null | cut -d= -f2) if [ -n "$limit" ]; then echo "$limit" return fi # Built-in defaults (keep in sync with first-boot-containers.sh) local low="${LOW_MEM:-false}" case "$name" in bitcoin-knots) $low && echo "1g" || echo "2g" ;; onlyoffice) $low && echo "1g" || echo "2g" ;; ollama) $low && echo "1g" || echo "4g" ;; lnd) echo "512m" ;; electrumx) echo "1g" ;; nextcloud) echo "1g" ;; immich_server) echo "1g" ;; btcpay-server) echo "1g" ;; homeassistant) echo "512m" ;; fedimint) echo "512m" ;; fedimint-gateway) echo "512m" ;; photoprism) $low && echo "512m" || echo "1g" ;; mempool-api) echo "512m" ;; jellyfin) echo "1g" ;; searxng) echo "512m" ;; archy-btcpay-db) echo "512m" ;; archy-nbxplorer) echo "512m" ;; archy-mempool-db) echo "512m" ;; archy-mempool-web) echo "256m" ;; grafana) echo "256m" ;; vaultwarden) echo "256m" ;; uptime-kuma) echo "256m" ;; filebrowser) echo "256m" ;; portainer) echo "256m" ;; nginx-proxy-manager) echo "256m" ;; immich_postgres) echo "256m" ;; immich_redis) echo "128m" ;; tailscale) echo "256m" ;; penpot-postgres) echo "256m" ;; penpot-valkey) echo "128m" ;; penpot-backend) echo "512m" ;; penpot-exporter) echo "256m" ;; penpot-frontend) echo "256m" ;; nostr-rs-relay) echo "256m" ;; strfry) echo "256m" ;; indeedhub|archy-bitcoin-ui|archy-lnd-ui|archy-electrs-ui) echo "128m" ;; *) echo "512m" ;; esac } # ── Wait for container readiness ─────────────────────────────────────── # Wait for a container health check command to succeed. # Usage: wait_for_container [max_wait_seconds] wait_for_container() { local name="$1" check_cmd="$2" max_wait="${3:-30}" local waited=0 while [ $waited -lt $max_wait ]; do if eval "$check_cmd" 2>/dev/null; then log_info "$name is ready (${waited}s)" return 0 fi sleep 2 waited=$((waited + 2)) done log_warn "$name not ready after ${max_wait}s" return 1 } # ── Section timing ───────────────────────────────────────────────────── # Track elapsed time for deploy sections. # Usage: # section_start "Building frontend" # ... do work ... # section_end _SECTION_START=0 _SECTION_NAME="" section_start() { _SECTION_NAME="${1:-}" _SECTION_START=$(date +%s) [ -n "$_SECTION_NAME" ] && log_info "$_SECTION_NAME" } section_end() { local elapsed=$(( $(date +%s) - _SECTION_START )) if [ -n "$_SECTION_NAME" ]; then log_info "$_SECTION_NAME done (${elapsed}s)" else echo " (${elapsed}s)" fi }