arr fleet: FrankBook-Pro is the sole deployment, all egress VPN-gated
FrankBook-Pro becomes the only *arr/qBittorrent deployment. Every fleet container (qB + five arrs) now shares gluetun's netns, so all egress — torrent, indexer APIs, metadata lookups — exits the WireGuard tunnel by construction (AllowedIPs=0.0.0.0/0); the arrs' own ports publish on the gluetun unit, none on the arr units themselves. - dankserver/compose.yaml: remove the six arr services (the Aug 20 compose copy — never healthy, superseded; config dirs trashed on the host) - dankclaw/Caddyfile + shared/homepage/services.json: arr vhosts and probes repoint 192.168.0.235 -> 192.168.0.112 (FrankBook-Pro) - frankbook-pro units: five arrs join gluetun netns (Wants/After/Network); gluetun publishes 9696/8989/7878/8686/8787 alongside 8080/6881 - tests/frankbook_quadlet.bats: new VPN egress seam — every arr+qB unit must share gluetun's netns and publish no port; gluetun must publish the whole fleet's ports - deploy-plan.py: gluetun changes carry the whole netns family (a gluetun recreation kills all six joiners); dankserver compose set loses the arrs - AGENTS.md: deployment is complete only when unit tests AND the Playwright E2E suite both pass
This commit is contained in:
@@ -2,9 +2,12 @@
|
||||
# Seam: the FrankBook-Pro quadlet units (gluetun, qbittorrent, five *arrs).
|
||||
# These units are installed INSIDE the Mac's podman machine VM by the
|
||||
# frankbook-pro handler in deploy-remote.sh. The contract pinned here:
|
||||
# boot persistence, self-healing, the gluetun netns invariant (qBittorrent
|
||||
# publishes no port of its own; gluetun publishes both), the verbatim
|
||||
# plan-locked data-root mounts, and zero literal secrets in tracked files.
|
||||
# boot persistence, self-healing, the VPN egress invariant (the whole
|
||||
# *arr fleet + qBittorrent share gluetun's netns and publish no ports of
|
||||
# their own, so ALL egress exits through the WireGuard tunnel —
|
||||
# AllowedIPs=0.0.0.0/0 — by construction; gluetun publishes every fleet
|
||||
# port), the verbatim plan-locked data-root mounts, and zero literal
|
||||
# secrets in tracked files.
|
||||
|
||||
load helpers
|
||||
|
||||
@@ -31,18 +34,22 @@ FRANKBOOK_UNITS=(
|
||||
done
|
||||
}
|
||||
|
||||
@test "qbittorrent joins gluetun's netns and publishes no port of its own" {
|
||||
local unit="$REPO_ROOT/frankbook-pro/qbittorrent/quadlet/qbittorrent.container"
|
||||
grep -q '^Network=gluetun.container$' "$unit" || return 1
|
||||
grep -q '^Wants=gluetun.service$' "$unit" || return 1
|
||||
grep -q '^After=gluetun.service$' "$unit" || return 1
|
||||
! grep -q '^PublishPort=' "$unit" || return 1
|
||||
@test "every arr and qbittorrent joins gluetun's netns and publishes no port" {
|
||||
local svc unit
|
||||
for svc in qbittorrent prowlarr sonarr radarr lidarr readarr; do
|
||||
unit="$REPO_ROOT/frankbook-pro/$svc/quadlet/$svc.container"
|
||||
grep -q '^Network=gluetun.container$' "$unit" || return 1
|
||||
grep -q '^Wants=gluetun.service$' "$unit" || return 1
|
||||
grep -q '^After=gluetun.service$' "$unit" || return 1
|
||||
! grep -q '^PublishPort=' "$unit" || return 1
|
||||
done
|
||||
}
|
||||
|
||||
@test "gluetun publishes qbittorrent's WebUI and torrent ports and needs NET_ADMIN+tun" {
|
||||
@test "gluetun publishes the whole fleet's ports and needs NET_ADMIN+tun" {
|
||||
local unit="$REPO_ROOT/frankbook-pro/gluetun/quadlet/gluetun.container"
|
||||
grep -q '^PublishPort=8080:8080$' "$unit" || return 1
|
||||
grep -q '^PublishPort=6881:6881$' "$unit" || return 1
|
||||
for port in 8080 6881 9696 8989 7878 8686 8787; do
|
||||
grep -q "^PublishPort=$port:$port\$" "$unit" || return 1
|
||||
done
|
||||
grep -q '^PublishPort=6881:6881/udp$' "$unit" || return 1
|
||||
grep -q '^AddCapability=NET_ADMIN$' "$unit" || return 1
|
||||
grep -q '^AddDevice=/dev/net/tun:/dev/net/tun$' "$unit" || return 1
|
||||
@@ -69,12 +76,7 @@ FRANKBOOK_UNITS=(
|
||||
grep -q '^Volume=/Volumes/INCOMPLETE:/Volumes/INCOMPLETE$' "$unit" || return 1
|
||||
}
|
||||
|
||||
@test "every arr serves its standard port and readarr keeps its pinned image" {
|
||||
grep -q '^PublishPort=9696:9696$' "$REPO_ROOT/frankbook-pro/prowlarr/quadlet/prowlarr.container" || return 1
|
||||
grep -q '^PublishPort=8989:8989$' "$REPO_ROOT/frankbook-pro/sonarr/quadlet/sonarr.container" || return 1
|
||||
grep -q '^PublishPort=7878:7878$' "$REPO_ROOT/frankbook-pro/radarr/quadlet/radarr.container" || return 1
|
||||
grep -q '^PublishPort=8686:8686$' "$REPO_ROOT/frankbook-pro/lidarr/quadlet/lidarr.container" || return 1
|
||||
grep -q '^PublishPort=8787:8787$' "$REPO_ROOT/frankbook-pro/readarr/quadlet/readarr.container" || return 1
|
||||
@test "readarr keeps its pinned image" {
|
||||
grep -q '^Image=lscr.io/linuxserver/readarr:amd64-1.0.980$' \
|
||||
"$REPO_ROOT/frankbook-pro/readarr/quadlet/readarr.container" || return 1
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user