feat(lobby): ship LuckPerms in the lobby image so the panel's permission controls work
The panel has a full permission surface — internal/api/handlers_access.go issues
`lp user <player> permission set/unset` and `lp user <player> parent add/remove`
over RCON, and projects the result back at
GET /api/v1/servers/{name}/access/luckperms/{player} — but nothing in this tree
ever installed LuckPerms. The lobby image copied felis-paper.jar into the plugin
directory and stopped there, so every grant the panel sent reached a server that
answered "Unknown command". Confirmed on the demo host: /data/plugins held only
FelisPaper/, bStats/, felis-paper.jar and spark/.
This is the other half of the RCON change. That one gave the control plane a
channel to send commands on; this one puts something at the far end that
understands them. Neither is useful alone.
The jar is resolved at build time rather than pinned in the Dockerfile, the same
way PAPER_JAR_URL already is: metadata.luckperms.net publishes the current build
for every platform, and asking upstream keeps this tree from going stale on every
LuckPerms release. Unlike Paper it is not version-matched to MC_VERSION — LuckPerms
ships one Bukkit build covering the whole supported Minecraft range, so there is no
per-version endpoint to ask. The resolver's pattern pins the /bukkit/loader/ path
segment deliberately: the metadata endpoint hands back the fabric, forge, velocity
and bukkit-legacy URLs in the same payload, and a looser match would happily return
a jar Paper cannot load, or the legacy build that targets Minecraft 1.8-1.12.
A missing LUCKPERMS_JAR_URL fails the build. That is a harsher default than the
RCON password, which only warns, and the difference is where the failure surfaces:
a lobby without RCON degrades visibly at once, whereas a lobby without LuckPerms
starts perfectly, runs perfectly, and only reveals itself when an owner tries to
grant somebody a permission. Build time is the cheap place to notice.
The entrypoint refreshes the jar from the image seed on every boot exactly as it
does for paper.jar and felis-paper.jar, so the executable artifact tracks the image
while LuckPerms' H2 database and config under plugins/LuckPerms/ stay on the PVC.
That split is the point: every grant ever issued lives in that directory, so the
refresh must never become a wipe.
Check: the three files that have to agree about LuckPerms — bootstrap.sh resolving
and passing the build-arg, the Dockerfile requiring that arg name and writing a
fixed path, the entrypoint copying from that same path — are pinned against each
other. Nothing compiles them together, and a typo in the path is invisible until a
lobby boots and `set -e` turns the failed cp into a crashloop on the hub every
authenticated player is transferred to. The test reads all three back out of the
embedded FS rather than off disk, since that is what the TUI install path ships.
Deployed installs are NOT fixed by this commit, for the same reason the RCON change
was not: the felis-lobby image has to be rebuilt and re-imported, and the pods
recreated, before the jar exists on the volume.
This commit is contained in:
4 files changed
+122
-5
No files matched your search
+17
-3
@@ -1,4 +1,4 @@
|
||||
# Felis lobby image: Paper + the felis-paper /menu plugin.
|
||||
# Felis lobby image: Paper + the felis-paper /menu plugin + LuckPerms.
|
||||
#
|
||||
# CODE-ONLY in this repo — not built by the Go CI. It packages the always-on
|
||||
# "lobby" hub the setup provisioner points [velocity] lobby_image at. The lobby is
|
||||
@@ -9,6 +9,8 @@
|
||||
# Fill v3 API — api.papermc.io v2 has returned HTTP 410 since 2026-07-01):
|
||||
# docker build -f deploy/lobby/Dockerfile \
|
||||
# --build-arg PAPER_JAR_URL=https://fill-data.papermc.io/v1/objects/<sha>/paper-26.2-<build>.jar \
|
||||
# --build-arg LUCKPERMS_JAR_URL="$(curl -fsSL https://metadata.luckperms.net/data/all \
|
||||
# | grep -o 'https://download.luckperms.net/[^"]*/bukkit/loader/[^"]*\.jar')" \
|
||||
# -t felis-lobby:demo .
|
||||
# docker save felis-lobby:demo | sudo k3s ctr images import -
|
||||
# # felis.toml → [velocity] lobby_image = "felis-lobby:demo"
|
||||
@@ -40,15 +42,27 @@ RUN cd plugins/paper \
|
||||
# also runs the plugin's Java-21 bytecode, so only the runtime moves.
|
||||
FROM eclipse-temurin:25-jre
|
||||
ARG PAPER_JAR_URL
|
||||
# LuckPerms is required, not optional: the panel's whole permission surface
|
||||
# (internal/api/handlers_access.go) issues `lp user ...` over RCON, so a lobby built
|
||||
# without it answers every grant with "Unknown command" — a failure the operator only
|
||||
# discovers in production, because the server itself starts and runs perfectly well.
|
||||
# Failing the build is the cheap place to notice. Resolved by URL rather than pinned
|
||||
# here for the same reason PAPER_JAR_URL is: bootstrap.sh asks upstream for the current
|
||||
# build, so this file does not go stale on every LuckPerms release.
|
||||
ARG LUCKPERMS_JAR_URL
|
||||
WORKDIR /paper
|
||||
RUN set -eu; \
|
||||
if [ -z "${PAPER_JAR_URL:-}" ]; then \
|
||||
echo "ERROR: --build-arg PAPER_JAR_URL=<paper jar> is required" >&2; exit 1; \
|
||||
fi; \
|
||||
if [ -z "${LUCKPERMS_JAR_URL:-}" ]; then \
|
||||
echo "ERROR: --build-arg LUCKPERMS_JAR_URL=<luckperms bukkit jar> is required" >&2; exit 1; \
|
||||
fi; \
|
||||
apt-get update && apt-get install -y --no-install-recommends curl ca-certificates; \
|
||||
curl -fSL "$PAPER_JAR_URL" -o /paper/paper.jar; \
|
||||
apt-get purge -y curl && apt-get autoremove -y && rm -rf /var/lib/apt/lists/*; \
|
||||
mkdir -p /paper/plugins; \
|
||||
curl -fSL "$PAPER_JAR_URL" -o /paper/paper.jar; \
|
||||
curl -fSL "$LUCKPERMS_JAR_URL" -o /paper/plugins/LuckPerms.jar; \
|
||||
apt-get purge -y curl && apt-get autoremove -y && rm -rf /var/lib/apt/lists/*; \
|
||||
echo "eula=true" > /paper/eula.txt
|
||||
COPY --from=plugin /felis-paper.jar /paper/plugins/felis-paper.jar
|
||||
# The entrypoint writes the Velocity modern-forwarding config (and REFUSES to start
|
||||
|
||||
@@ -43,6 +43,10 @@ fi
|
||||
mkdir -p "$DATA_DIR/plugins"
|
||||
cp -f "$RUNTIME_DIR/paper.jar" "$DATA_DIR/paper.jar"
|
||||
cp -f "$RUNTIME_DIR/plugins/felis-paper.jar" "$DATA_DIR/plugins/felis-paper.jar"
|
||||
# Only the jar is refreshed — LuckPerms keeps its H2 database and config under
|
||||
# $DATA_DIR/plugins/LuckPerms/, which is exactly the state the PVC exists to preserve.
|
||||
# Every grant the panel has ever issued lives there, so this must never be a wipe.
|
||||
cp -f "$RUNTIME_DIR/plugins/LuckPerms.jar" "$DATA_DIR/plugins/LuckPerms.jar"
|
||||
printf 'eula=true\n' > "$DATA_DIR/eula.txt"
|
||||
cd "$DATA_DIR"
|
||||
|
||||
|
||||
Reference in new issue
Block a user