feat(sterni/machines/ingeborg): regularly back up minecraft worlds
This is just intended as a local backup in case things go wrong horribly, so you can revert to a recent state. Change-Id: I1d666bad77045a1c807204df144422ba69d1d99f Reviewed-on: https://cl.tvl.fyi/c/depot/+/10417 Autosubmit: sterni <sternenseemann@systemli.org> Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
This commit is contained in:
parent
d4dc28b675
commit
32e8e16e1e
2 changed files with 131 additions and 2 deletions
|
@ -38,11 +38,10 @@ let
|
|||
};
|
||||
in
|
||||
|
||||
# TODO(sterni): regular backups of carpet world
|
||||
|
||||
{
|
||||
imports = [
|
||||
../../modules/minecraft-fabric.nix
|
||||
../../modules/backup-minecraft-fabric.nix
|
||||
];
|
||||
|
||||
config = {
|
||||
|
@ -65,6 +64,11 @@ in
|
|||
minecraft-rcon.file = depot.users.sterni.secrets."minecraft-rcon.age";
|
||||
};
|
||||
|
||||
services.backup-minecraft-fabric-servers = {
|
||||
enable = true;
|
||||
repository = "/srv/backup/from-local/minecraft";
|
||||
};
|
||||
|
||||
services.minecraft-fabric-server = {
|
||||
creative = {
|
||||
enable = false; # not actively used
|
||||
|
|
125
users/sterni/modules/backup-minecraft-fabric.nix
Normal file
125
users/sterni/modules/backup-minecraft-fabric.nix
Normal file
|
@ -0,0 +1,125 @@
|
|||
# Companion module to minecraft-fabric.nix which automatically and regularly
|
||||
# creates backups of all minecraft servers' worlds to a shared borg(1)
|
||||
# repository.
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: 2023 sterni <sternenseemann@systemli.org>
|
||||
{ pkgs, depot, config, lib, ... }:
|
||||
|
||||
let
|
||||
inherit (depot.nix) getBins;
|
||||
|
||||
bins = getBins pkgs.borgbackup [ "borg" ]
|
||||
// getBins pkgs.mcrcon [ "mcrcon" ];
|
||||
|
||||
unvaried = ls: builtins.all (l: l == builtins.head ls) ls;
|
||||
|
||||
cfg = config.services.backup-minecraft-fabric-servers;
|
||||
|
||||
instances = lib.filterAttrs (_: i: i.enable) config.services.minecraft-fabric-server;
|
||||
users = lib.mapAttrsToList (_: i: i.user) instances;
|
||||
groups = lib.mapAttrsToList (_: i: i.group) instances;
|
||||
|
||||
mkBackupScript = instanceName: instanceCfg:
|
||||
let
|
||||
archivePrefix = "minecraft-fabric-${instanceName}-world-${builtins.baseNameOf instanceCfg.world}-";
|
||||
in
|
||||
|
||||
pkgs.writeShellScript "backup-minecraft-fabric-${instanceName}" ''
|
||||
export MCRCON_HOST="localhost"
|
||||
export MCRCON_PORT="${toString instanceCfg.serverProperties."rcon.port"}"
|
||||
# Unfortunately, mcrcon can't read the password from a file
|
||||
export MCRCON_PASS="$(cat "''${CREDENTIALS_DIRECTORY}/${instanceName}-rcon-password")"
|
||||
|
||||
${bins.mcrcon} save-all
|
||||
unset MCRCON_PASS
|
||||
|
||||
# Give the server plenty of time to save
|
||||
sleep 60
|
||||
|
||||
${bins.borg} ${lib.escapeShellArgs [
|
||||
"create"
|
||||
"--verbose" "--filter" "AMEU" "--list"
|
||||
"--stats" "--show-rc"
|
||||
"--compression" "zlib"
|
||||
"${cfg.repository}::${archivePrefix}{now}"
|
||||
instanceCfg.world
|
||||
]}
|
||||
|
||||
${bins.borg} ${lib.escapeShellArgs [
|
||||
"prune"
|
||||
"--list"
|
||||
"--show-rc"
|
||||
"--glob-archives" "${archivePrefix}*"
|
||||
"--keep-hourly" "168"
|
||||
"--keep-daily" "31"
|
||||
"--keep-monthly" "6"
|
||||
"--keep-yearly" "2"
|
||||
cfg.repository
|
||||
]}
|
||||
|
||||
${bins.borg} compact ${lib.escapeShellArg cfg.repository}
|
||||
'';
|
||||
in
|
||||
|
||||
{
|
||||
imports = [
|
||||
./minecraft-fabric.nix
|
||||
];
|
||||
|
||||
options = {
|
||||
services.backup-minecraft-fabric-servers = {
|
||||
enable = lib.mkEnableOption "backups of all Minecraft fabric servers";
|
||||
|
||||
repository = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
description = "Path to the borg(1) repository to use for all backups.";
|
||||
default = "/var/lib/backup/minecraft-fabric";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf (cfg.enable && builtins.length (builtins.attrNames instances) > 0) {
|
||||
assertions = [
|
||||
{
|
||||
assertion = unvaried users && unvaried groups;
|
||||
message = "all instances under services.minecraft-fabric-server must use the same user and group";
|
||||
}
|
||||
];
|
||||
|
||||
environment.systemPackages = [
|
||||
pkgs.borgbackup
|
||||
];
|
||||
|
||||
systemd = {
|
||||
services.backup-minecraft-fabric-servers = {
|
||||
description = "Backup world of all fabric based Minecraft servers";
|
||||
wantedBy = [ ];
|
||||
after = builtins.map
|
||||
(name: "minecraft-fabric-${name}.service")
|
||||
(builtins.attrNames instances);
|
||||
|
||||
script = lib.concatStrings (lib.mapAttrsToList mkBackupScript instances);
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = builtins.head users;
|
||||
Group = builtins.head groups;
|
||||
LoadCredential = lib.mapAttrsToList
|
||||
(instanceName: instanceCfg: "${instanceName}-rcon-password:${instanceCfg.rconPasswordFile}")
|
||||
instances;
|
||||
};
|
||||
};
|
||||
|
||||
timers.backup-minecraft-fabric-servers = {
|
||||
description = "Regularly backup Minecraft fabric servers";
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = {
|
||||
OnCalendar = "*-*-* 00/3:00:00";
|
||||
Persistent = true;
|
||||
RandomizedDelaySec = "1h";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue