modules/backup: add backup module using restic
This commit is contained in:
parent
2ab99d861a
commit
05a2742a91
@ -117,6 +117,13 @@
|
||||
|
||||
clerie.nixfiles.enable = true;
|
||||
|
||||
clerie.backup = {
|
||||
targets = {
|
||||
cyan.serverName = "cyan.backup.clerie.de";
|
||||
magenta.serverName = "magenta.backup.clerie.de";
|
||||
};
|
||||
};
|
||||
|
||||
nixpkgs.overlays = [
|
||||
(import ../../pkgs/overlay.nix)
|
||||
];
|
||||
|
@ -51,15 +51,14 @@ in {
|
||||
};
|
||||
};
|
||||
|
||||
services.restic.backups = {
|
||||
main = {
|
||||
paths = [
|
||||
"/var/src"
|
||||
"/var/lib"
|
||||
];
|
||||
initialize = true;
|
||||
passwordFile = "/var/src/secrets/restic/main";
|
||||
repositoryFile = "/var/src/secrets/restic/repository-cyan";
|
||||
clerie.backup = {
|
||||
enable = true;
|
||||
jobs = {
|
||||
main = {
|
||||
paths = [
|
||||
"/var/lib"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
120
modules/backup/default.nix
Normal file
120
modules/backup/default.nix
Normal file
@ -0,0 +1,120 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.clerie.backup;
|
||||
|
||||
jobTargetPairs = flatten (
|
||||
mapAttrsToList (jobName: jobOptions:
|
||||
let
|
||||
jobTargets = if jobOptions.targets == null then cfg.targets
|
||||
else
|
||||
filterAttrs (targetName: targetOptions:
|
||||
any (map (jobOptionTarget: jobOptionTarget == targetName) jobOptions.targets)
|
||||
) cfg.targets;
|
||||
in mapAttrsToList (targetName: targetOptions:
|
||||
{
|
||||
inherit jobName jobOptions targetName targetOptions;
|
||||
}
|
||||
) jobTargets
|
||||
) cfg.jobs
|
||||
);
|
||||
|
||||
backupServiceUnits = listToAttrs (map ({jobName, jobOptions, targetName, targetOptions}: let
|
||||
jobPasswordFile = if jobOptions.passwordFile == null then config.age.secrets."clerie-backup-job-${jobName}".path else jobOptions.passwordFile;
|
||||
repoPath = if jobOptions.repoPath == null then "/${config.networking.hostName}/${jobName}" else jobOptions.repoPath;
|
||||
targetPasswordFile = if targetOptions.passwordFile == null then config.age.secrets."clerie-backup-target-${targetName}".path else targetOptions.passwordFile;
|
||||
targetUsername = if targetOptions.username == null then config.networking.hostName else targetOptions.username;
|
||||
in
|
||||
nameValuePair "clerie-backup-${jobName}-${targetName}" {
|
||||
requires = [ "network.target" "local-fs.target" ];
|
||||
path = [ pkgs.restic ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
};
|
||||
|
||||
script = ''
|
||||
set -euo pipefail
|
||||
|
||||
export RESTIC_PASSWORD_FILE=${jobPasswordFile}
|
||||
export RESTIC_REPOSITORY="rest:https://${targetUsername}:$(cat ${targetPasswordFile})@${targetOptions.serverName}${repoPath}"
|
||||
|
||||
restic snapshots || restic init
|
||||
|
||||
restic backup ${escapeShellArgs jobOptions.paths}
|
||||
|
||||
restic check
|
||||
'';
|
||||
}
|
||||
) jobTargetPairs);
|
||||
|
||||
backupServiceTimers = listToAttrs (map ({jobName, jobOptions, targetName, targetOptions}:
|
||||
nameValuePair "clerie-backup-${jobName}-${targetName}" {
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = {
|
||||
OnCalendar = "hourly";
|
||||
RandomizedDelaySec = "1h";
|
||||
};
|
||||
after = [ "network-online.target" ];
|
||||
}
|
||||
) jobTargetPairs);
|
||||
|
||||
targetOptions = { ... }: {
|
||||
options = {
|
||||
passwordFile = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
};
|
||||
username = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
};
|
||||
serverName = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
jobOptions = { ... }: {
|
||||
options = {
|
||||
passwordFile = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
};
|
||||
repoPath = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
};
|
||||
targets = mkOption {
|
||||
type = with types; nullOr (listOf str);
|
||||
default = null;
|
||||
};
|
||||
paths = mkOption {
|
||||
type = with types; listOf str;
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
clerie.backup = {
|
||||
enable = mkEnableOption "clerie's Backup";
|
||||
targets = mkOption {
|
||||
type = with types; attrsOf (submodule targetOptions);
|
||||
default = {};
|
||||
};
|
||||
jobs = mkOption {
|
||||
type = with types; attrsOf (submodule jobOptions);
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services = backupServiceUnits;
|
||||
systemd.timers = backupServiceTimers;
|
||||
};
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
./policyrouting
|
||||
./akne
|
||||
./anycast_healthchecker
|
||||
./backup
|
||||
./clerie-firewall
|
||||
./gre-tunnel
|
||||
./minecraft-server
|
||||
|
Loading…
Reference in New Issue
Block a user