ctucx.git: nixfiles

ctucx' nixfiles

commit ae494a36a6467b28f55fd5c96c9cec0868a0332c
parent f8ce2d089d024d203d98195fd7b9333ef0b21b58
Author: Leah (ctucx) <leah@ctu.cx>
Date: Thu, 27 Jan 2022 18:10:21 +0100

modules: add restic-backup module
2 files changed, 141 insertions(+), 0 deletions(-)
A
modules/default.nix
|
7
+++++++
A
modules/restic-backups.nix
|
134
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
diff --git a/modules/default.nix b/modules/default.nix
@@ -0,0 +1,7 @@
+{
+
+  imports = [
+    ./restic-backups.nix
+  ];
+
+}
diff --git a/modules/restic-backups.nix b/modules/restic-backups.nix
@@ -0,0 +1,134 @@
+{ options, config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  backups = config.restic-backups;
+
+  backupOpts = { ... }: {
+    options = {
+
+      user = mkOption {
+        type    = types.str;
+        default = "root";
+      };
+
+      passwordFile = mkOption {
+        type = types.str;
+      };
+
+      paths = mkOption {
+        type    = with types; listOf str;
+        default = [];
+      };
+
+      postgresDatabases = mkOption {
+        type    = with types; listOf str;
+        default = [];
+      };
+
+      timerConfig = mkOption {
+        type    = types.attrs;
+        default = {
+          OnCalendar         = "daily";
+          RandomizedDelaySec = 300;
+        };
+      };
+
+    };
+  };
+
+  servers = [ "desastro.ctu.cx" "lollo.ctu.cx" ];
+
+in {
+
+  options.restic-backups = mkOption {
+    type    = with types; attrsOf (submodule backupOpts);
+    default = {};
+  };
+
+  config = mkIf (backups != {}) {
+
+    systemd.services = mapAttrs' (
+      name: backup: nameValuePair "restic-backup-${name}" {
+        restartIfChanged = false;
+        requires         = [ "network.target" "local-fs.target" ];
+        onFailure        = [ "notify-failure@%i.service" ];
+
+        path = [
+          pkgs.restic
+        ] ++ optionals (backup.postgresDatabases != []) [
+          config.services.postgresql.package
+          pkgs.zstd
+        ];
+
+        serviceConfig    = {
+          Type               = "oneshot";
+          User               = backup.user;
+          RuntimeDirectory   = "restic-backup-${name}";
+          CacheDirectory     = "restic-backup-${name}";
+          CacheDirectoryMode = "0700";
+          ReadWritePaths     = backup.paths;
+          PrivateTmp         = true;
+          ProtectHome        = true;
+          ProtectSystem      = "strict";
+          Environment        = "RESTIC_PASSWORD_FILE=/tmp/passwordFile";
+          ExecStartPre = [
+            (
+              "!" + (pkgs.writeScript "privileged-pre-start" (''
+                #!${pkgs.runtimeShell}
+                set -eu pipefail
+
+                cp ${backup.passwordFile} /tmp/passwordFile;
+                cp /run/agenix/restic-server-lollo    /tmp/lollo.ctu.cx;
+                cp /run/agenix/restic-server-desastro /tmp/desastro.ctu.cx;
+
+                chown -R ${backup.user} /tmp
+              ''))
+            )
+            (
+              pkgs.writeScript "pre-start" (''
+                #!${pkgs.runtimeShell}
+                set -eu pipefail
+
+                '' + concatMapStringsSep "\n" (db: ''
+                echo "Dumping Postgres-database: ${db}"
+                mkdir -p /tmp/postgresDatabases
+                pg_dump ${db} | zstd --rsyncable > /tmp/postgresDatabases/${db}.sql.zst
+                [ $(du -b /tmp/postgresDatabases/${db}.sql.zst | cut -f1) -gt "50" ] || exit 1
+              '') backup.postgresDatabases)
+            )
+          ];
+        };
+
+        script = ''
+          set -eu pipefail
+          export XDG_CACHE_HOME=/var/cache/restic-backup-${name}
+
+        '' + concatMapStringsSep "\n\n" (server: ''
+          echo "Backing up to: ${server}"
+
+          export RESTIC_REPOSITORY="rest:https://restic:$(cat /tmp/${server})@restic.${server}/${config.networking.hostName}-${name}"
+
+          #create repo if it not exists
+          restic snapshots || restic init
+
+          #backup files
+          restic backup ${concatStringsSep " " (backup.paths ++ optional (backup.postgresDatabases != []) "/tmp/postgresDatabases") }
+
+          restic check
+        '') servers;
+
+      }
+    ) backups;
+
+    systemd.timers = mapAttrs' (
+      name: backup: nameValuePair "restic-backup-${name}" {
+        wantedBy    = [ "timers.target" ];
+        timerConfig = backup.timerConfig;
+      }
+    ) backups;
+
+  };
+
+}