From 3003c8cdac93024181d36f579a06c3e737765c25 Mon Sep 17 00:00:00 2001 From: Gabriel Fontes Date: Sun, 29 Dec 2024 18:09:08 -0300 Subject: [PATCH] module: refactor file & symlink (#116) 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) --- modules/minecraft-servers.nix | 89 ++++++++++++++++++++--------------- tests/files-symlinks.nix | 5 ++ 2 files changed, 57 insertions(+), 37 deletions(-) diff --git a/modules/minecraft-servers.nix b/modules/minecraft-servers.nix index 7ea3c6dd..a890c04a 100644 --- a/modules/minecraft-servers.nix +++ b/modules/minecraft-servers.nix @@ -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 + + (i.e. @variable_name@). ''; managementSystem = mkOption { @@ -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} @@ -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"; diff --git a/tests/files-symlinks.nix b/tests/files-symlinks.nix index 43bfe37c..52baf871 100644 --- a/tests/files-symlinks.nix +++ b/tests/files-symlinks.nix @@ -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") ''; }