podman 5.7 podman-user-generator on dankserver hard-fails the whole unit on
the unknown key ('unsupported key UsernsMode in group Container'), so the
first cutover attempt masked the native unit and then found no plex.service
at all. Swap both units to UserNS=host (same --userns=host flag), update the
ownership-contract seam test to pin the exact key, and correct both docs.
Pin the seam: the v1 generator rejects unknown Container keys silently at
deploy distance — the test now pins UserNS=, not the misspelled alias.
81 lines
4.7 KiB
Bash
Executable File
81 lines
4.7 KiB
Bash
Executable File
#!/usr/bin/env bats
|
|
# Seam: the eight cutover-era dankserver quadlet units (romm trio, jellyfin,
|
|
# calibre-web, copyparty, plex, tautulli) must keep their boot-persistence and v1-generator
|
|
# contracts. The podman 5.x v1 Quadlet generator silently drops or hard-fails
|
|
# on several keys; these tests pin the contract that keeps the units loadable
|
|
# and secret-free in the repo.
|
|
|
|
load helpers
|
|
|
|
@test "all eight cutover units exist under dankserver/<svc>/quadlet/" {
|
|
for unit in romm/quadlet/romm romm/quadlet/romm-mariadb romm/quadlet/romm-redis jellyfin/quadlet/jellyfin calibre-web/quadlet/calibre-web copyparty/quadlet/copyparty plex/quadlet/plex tautulli/quadlet/tautulli; do
|
|
[ -f "$REPO_ROOT/dankserver/$unit.container" ] || return 1
|
|
done
|
|
}
|
|
|
|
@test "every cutover unit is boot-persistent (WantedBy=default.target)" {
|
|
for unit in romm/quadlet/romm romm/quadlet/romm-mariadb romm/quadlet/romm-redis jellyfin/quadlet/jellyfin calibre-web/quadlet/calibre-web copyparty/quadlet/copyparty plex/quadlet/plex tautulli/quadlet/tautulli; do
|
|
grep -q '^WantedBy=default.target$' "$REPO_ROOT/dankserver/$unit.container" || return 1
|
|
done
|
|
}
|
|
|
|
@test "copyparty uses Exec= not Command= (v1 generator hard-fails on Command=)" {
|
|
unit="$REPO_ROOT/dankserver/copyparty/quadlet/copyparty.container"
|
|
grep -q '^Command=' "$unit" && return 1
|
|
grep -q '^Exec=-a ${COPAY_ACCOUNT}:${COPAY_PASSWORD}' "$unit" || return 1
|
|
}
|
|
|
|
@test "copyparty and romm consume host-local env files, never in-repo secrets" {
|
|
grep -q '^EnvironmentFile=/home/dank/Containers/copyparty/env$' \
|
|
"$REPO_ROOT/dankserver/copyparty/quadlet/copyparty.container" || return 1
|
|
for unit in romm/quadlet/romm romm/quadlet/romm-mariadb; do
|
|
grep -q '^EnvironmentFile=/home/dank/Containers/romm/env$' \
|
|
"$REPO_ROOT/dankserver/$unit.container" || return 1
|
|
done
|
|
# No literal credential may ever appear in a tracked unit file: the only
|
|
# Exec= arguments must be variable expansions, never a literal account:secret.
|
|
! grep -qE '\-a [A-Za-z0-9]+:[A-Za-z0-9]' "$REPO_ROOT/dankserver/copyparty/quadlet/copyparty.container" || return 1
|
|
}
|
|
|
|
@test "romm db services keep their service-discovery aliases on the appnet" {
|
|
grep -q '^Network=dankserver_appnet:alias=mariadb$' \
|
|
"$REPO_ROOT/dankserver/romm/quadlet/romm-mariadb.container" || return 1
|
|
grep -q '^Network=dankserver_appnet:alias=redis$' \
|
|
"$REPO_ROOT/dankserver/romm/quadlet/romm-redis.container" || return 1
|
|
}
|
|
|
|
@test "no unit uses the unsupported Device= key (v1 generator needs AddDevice=)" {
|
|
# A rejected file kills its own unit silently: the deploy would then die
|
|
# with "Unit jellyfin.service not found" only on the target. Device= was
|
|
# the first offender (jellyfin GPU passthrough); Command= is guarded
|
|
# above. Keep this list current with every generator finding.
|
|
for unit in dankserver/romm/quadlet/romm dankserver/romm/quadlet/romm-mariadb \
|
|
dankserver/romm/quadlet/romm-redis dankserver/jellyfin/quadlet/jellyfin \
|
|
dankserver/calibre-web/quadlet/calibre-web dankserver/copyparty/quadlet/copyparty \
|
|
dankserver/plex/quadlet/plex dankserver/tautulli/quadlet/tautulli; do
|
|
! grep -q '^Device=' "$REPO_ROOT/$unit.container" || return 1
|
|
done
|
|
grep -q '^AddDevice=/dev/dri$' "$REPO_ROOT/dankserver/jellyfin/quadlet/jellyfin.container" || return 1
|
|
}
|
|
|
|
@test "every host-served port is explicitly published (no silent bridge-only)" {
|
|
grep -q '^PublishPort=8085:8080$' "$REPO_ROOT/dankserver/romm/quadlet/romm.container" || return 1
|
|
grep -q '^PublishPort=8096:8096$' "$REPO_ROOT/dankserver/jellyfin/quadlet/jellyfin.container" || return 1
|
|
grep -q '^PublishPort=8083:8083$' "$REPO_ROOT/dankserver/calibre-web/quadlet/calibre-web.container" || return 1
|
|
grep -q '^PublishPort=3923:3923$' "$REPO_ROOT/dankserver/copyparty/quadlet/copyparty.container" || return 1
|
|
grep -q '^PublishPort=32400:32400$' "$REPO_ROOT/dankserver/plex/quadlet/plex.container" || return 1
|
|
grep -q '^PublishPort=8181:8181$' "$REPO_ROOT/dankserver/tautulli/quadlet/tautulli.container" || return 1
|
|
}
|
|
|
|
@test "plex keeps the native unit's identity (UserNS=host, PUID=997, PGID=984)" {
|
|
# Zero-chown ownership contract: /var/lib/plexmediaserver is bind-mounted
|
|
# in place, so every file the container writes must land owned 997:984 —
|
|
# byte-identical to the former plexmediaserver.service identity. UserNS=
|
|
# is the quadlet v1 key (UsernsMode= is compose syntax and the generator
|
|
# hard-fails the whole unit on it); pin the exact keys.
|
|
unit="$REPO_ROOT/dankserver/plex/quadlet/plex.container"
|
|
grep -q '^UserNS=host$' "$unit" || return 1
|
|
grep -q '^Environment=PUID=997$' "$unit" || return 1
|
|
grep -q '^Environment=PGID=984$' "$unit" || return 1
|
|
}
|