1
0
nixfiles/modules/backup/default.nix

121 lines
3.3 KiB
Nix
Raw Normal View History

{ 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;
};
}