#!/usr/bin/env bash set -euo pipefail [[ "$#" -eq 4 ]] || { echo "usage: deploy-valheim-klops.sh HOST PORT WG_IPV4 WG_IPV6" >&2 exit 2 } host="$1" port="$2" wg_ipv4="$3" wg_ipv6="$4" [[ "$port" =~ ^[0-9]+$ && "$wg_ipv4" = 10.100.0.2 && "$wg_ipv6" = fd00:100::2 ]] || { echo "invalid Valheim ingress input" >&2 exit 2 } repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" ssh -p "$port" "root@${host}" 'bash -s -- 10.100.0.2 fd00:100::2' \ <"$repo_root/scripts/remote/apply-valheim-klops-firewall.sh" owner_env="${PUFFER_OWNER_ENV:-$repo_root/keys/pufferpanel-owner.env}" [[ -f "$owner_env" && ! -L "$owner_env" && "$(stat -c %a "$owner_env")" = 600 ]] || { echo "missing owner credential file with mode 0600" >&2 exit 1 } umask 077 scratch_root=/var/tmp/pufferpanel-fork/valheim-ingress-klops install -d -m 0700 "$scratch_root" scratch="$(mktemp -d "$scratch_root/run.XXXXXX")" definition="$scratch/definition.json" body="$scratch/body.json" login_body="$scratch/login.json" cookie_jar="$scratch/cookies.txt" status_body="$scratch/status.json" : >"$cookie_jar" chmod 0600 "$cookie_jar" cleanup() { if [[ -n "${base_url:-}" ]]; then curl --silent --show-error --connect-timeout 10 --max-time 30 --cookie "$cookie_jar" --cookie-jar "$cookie_jar" \ -X POST "$base_url/auth/logout" >/dev/null 2>&1 || true fi rm -rf -- "$scratch" } trap cleanup EXIT # shellcheck disable=SC1090 source "$owner_env" : "${PUFFER_OWNER_EMAIL:?missing PUFFER_OWNER_EMAIL}" : "${PUFFER_OWNER_PASSWORD:?missing PUFFER_OWNER_PASSWORD}" : "${PUFFER_OWNER_URL:?missing PUFFER_OWNER_URL}" base_url="${PUFFER_OWNER_URL%/}" [[ "$base_url" = https://games.bugabinga.net ]] || { echo "unexpected PufferPanel URL" >&2 exit 1 } export PUFFER_OWNER_EMAIL PUFFER_OWNER_PASSWORD jq -n '{email: env.PUFFER_OWNER_EMAIL, password: env.PUFFER_OWNER_PASSWORD}' >"$login_body" curl --fail --silent --show-error --connect-timeout 10 --max-time 30 --cookie "$cookie_jar" --cookie-jar "$cookie_jar" \ -H 'Content-Type: application/json' --data-binary "@$login_body" "$base_url/auth/login" >/dev/null api() { curl --fail --silent --show-error --connect-timeout 10 --max-time 30 --cookie "$cookie_jar" --cookie-jar "$cookie_jar" \ -H 'Content-Type: application/json' "$@" } read_status() { api "$base_url/api/servers/valheim1/status" >"$status_body" jq -e 'type == "object" and (.running | type == "boolean") and (.installing | type == "boolean")' "$status_body" >/dev/null } is_running() { jq -e '.running == true' "$status_body" >/dev/null } assert_not_installing() { jq -e '.installing == false' "$status_body" >/dev/null || { echo 'Valheim is installing; definition unchanged' >&2 return 1 } } poll_stopped() { for _ in $(seq 1 24); do read_status assert_not_installing is_running || return 0 sleep 5 done echo 'Valheim did not stop within 120 seconds; definition unchanged' >&2 return 1 } poll_running() { for _ in $(seq 1 60); do read_status assert_not_installing is_running && return 0 sleep 5 done echo 'Valheim did not report running within 300 seconds after restart' >&2 return 1 } api "$base_url/api/servers/valheim1/definition" >"$definition" read_status assert_not_installing was_running=false is_running && was_running=true bindings="$(jq -cn --arg v4 "$wg_ipv4" --arg v6 "$wg_ipv6" '[ $v4 + ":2456:2456/udp", "[" + $v6 + "]:2456:2456/udp", $v4 + ":2457:2457/udp", "[" + $v6 + "]:2457:2457/udp" ]')" if jq -e --argjson bindings "$bindings" '.environment.portBindings == $bindings' "$definition" >/dev/null; then printf '%s\n' 'Valheim port bindings already reconciled' exit 0 fi if "$was_running"; then api -X POST "$base_url/api/servers/valheim1/stop" >/dev/null poll_stopped fi timestamp="$(date -u +%Y%m%dT%H%M%SZ)" backup="/data/pufferpanel/data/backups/valheim-ingress-${timestamp}" ssh -p "$port" "root@${host}" "install -d -m 0700 -o pufferpanel -g pufferpanel '$backup' && runuser -u pufferpanel -- sh -c 'umask 077; cat > \"$backup/definition.json\"; cp -a /data/pufferpanel/data/servers/valheim1/saves \"$backup/saves\"'" <"$definition" jq --argjson bindings "$bindings" '.environment.portBindings = $bindings' "$definition" >"$body" api -X PUT --data-binary "@$body" "$base_url/api/servers/valheim1/definition" >/dev/null if "$was_running"; then api -X POST "$base_url/api/servers/valheim1/start" >/dev/null poll_running fi printf 'changed: Valheim definition and backup %s\n' "$backup"