Skip to content

Commit

Permalink
module: refactor file & symlink (#116)
Browse files Browse the repository at this point in the history
The new system works by adding a file (.nix-minecraft-managed) to track managed files and symlinks. This makes it possible to correctly cleanup managed files (when stopping, restarting, reloading).

I've also added support for directories (#73), and ensured only non-binary files are substituted with env vars (#70)
  • Loading branch information
Misterio77 authored Dec 29, 2024
1 parent 6d93447 commit 3003c8c
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 37 deletions.
89 changes: 52 additions & 37 deletions modules/minecraft-servers.nix
Original file line number Diff line number Diff line change
Expand Up @@ -483,9 +483,15 @@ in
arbitrary files in the server's data directory.
'';
files = with types; mkOpt' (attrsOf (either path configType)) { } ''
Things to copy into this server's data directory. Similar to
symlinks, but these are actual files. Useful for configuration
files that don't behave well when read-only.
Things to copy into this server's data directory. Similar to symlinks,
but these are actual, writable, files. Useful for configuration files
that don't behave well when read-only. Directories are copied recursively and
dereferenced. They will be deleted after the server stops, so any modification
is discarded.
These files may include placeholders to substitute with values from
<option>services.minecraft-servers.environmentFile</option>
(i.e. @variable_name@).
'';

managementSystem = mkOption {
Expand Down Expand Up @@ -610,45 +616,62 @@ in

msConfig = managementSystemConfig name conf;

markManaged = file: ''echo "${file}" >> .nix-minecraft-managed'';
cleanAllManaged = ''
if [ -e .nix-minecraft-managed ]; then
readarray -t to_delete < .nix-minecraft-managed
rm -rf "''${to_delete[@]}"
rm .nix-minecraft-managed
fi
'';


ExecStartPre =
let
backup = file: ''
if [[ -e "${file}" ]]; then
echo "${file} already exists, moving"
mv "${file}" "${file}.bak"
fi
'';
mkSymlinks = concatStringsSep "\n"
(mapAttrsToList
(n: v: ''
if [[ -L "${n}" ]]; then
unlink "${n}"
elif [[ -e "${n}" ]]; then
echo "${n} already exists, moving"
mv "${n}" "${n}.bak"
fi
${backup n}
mkdir -p "$(dirname "${n}")"
ln -sf "${v}" "${n}"
${markManaged n}
'')
symlinks);

mkFiles = concatStringsSep "\n"
(mapAttrsToList
(n: v: ''
if [[ -L "${n}" ]]; then
unlink "${n}"
elif ${pkgs.diffutils}/bin/cmp -s "${n}" "${v}"; then
rm "${n}"
elif [[ -e "${n}" ]]; then
echo "${n} already exists, moving"
mv "${n}" "${n}.bak"
fi
${backup n}
mkdir -p "$(dirname "${n}")"
${pkgs.gawk}/bin/awk '{
for(varname in ENVIRON)
gsub("@"varname"@", ENVIRON[varname])
print
}' "${v}" > "${n}"
# If it's not a binary, substitute env vars. Else, copy it normally
if ${pkgs.file}/bin/file --mime-encoding "${v}" | grep -v '\bbinary$' -q; then
${pkgs.gawk}/bin/awk '{
for(varname in ENVIRON)
gsub("@"varname"@", ENVIRON[varname])
print
}' "${v}" > "${n}"
else
cp -r --dereference "${v}" -T "${n}"
chmod +w -R "${n}"
fi
${markManaged n}
'')
files);
in
getExe (pkgs.writeShellApplication {
name = "minecraft-server-${name}-start-pre";
text = ''
${cleanAllManaged}
${mkSymlinks}
${mkFiles}
${conf.extraStartPre}
Expand Down Expand Up @@ -680,21 +703,13 @@ in
'';
});

ExecStopPost =
let
rmSymlinks = concatStringsSep "\n"
(mapAttrsToList (n: v: "unlink \"${n}\"") symlinks);
rmFiles = concatStringsSep "\n"
(mapAttrsToList (n: v: "rm -f \"${n}\"") files);
in
getExe (pkgs.writeShellApplication {
name = "minecraft-server-${name}-stop-post";
text = ''
${rmSymlinks}
${rmFiles}
${conf.extraStopPost}
'';
});
ExecStopPost = getExe (pkgs.writeShellApplication {
name = "minecraft-server-${name}-stop-post";
text = ''
${cleanAllManaged}
${conf.extraStopPost}
'';
});

ExecReload = getExe (pkgs.writeShellApplication {
name = "minecraft-server-${name}-reload";
Expand Down
5 changes: 5 additions & 0 deletions tests/files-symlinks.nix
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,10 @@ nixosTest {
# Check that de-opping works (ops.json is mutable as expected)
server.succeed(server_cmd("deop Misterio7x"))
server.wait_until_succeeds(grep_logs("Made Misterio7x no longer a server operator"), timeout=3)
# Check that cleanup works
server.wait_until_succeeds(f"systemctl stop minecraft-server-{name}.service")
server.fail(f"test -e /srv/minecraft/{name}/cache/mojang_1.19.4.jar")
server.fail(f"test -e /srv/minecraft/{name}/ops.json")
'';
}

0 comments on commit 3003c8c

Please sign in to comment.