163 lines
3.9 KiB
Nix
163 lines
3.9 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
options,
|
|
...
|
|
}:
|
|
let
|
|
inherit (lib)
|
|
mkIf
|
|
mkEnableOption
|
|
mkOption
|
|
concatStringsSep
|
|
toList
|
|
listToAttrs
|
|
;
|
|
inherit (lib.types)
|
|
listOf
|
|
nonEmptyStr
|
|
package
|
|
str
|
|
port
|
|
bool
|
|
submoduleWith
|
|
;
|
|
inherit (lib.my) slugify;
|
|
cfg = config.modules.services.rsync-backup;
|
|
in
|
|
{
|
|
# Used to back up multiple source destinations to a target destination regularly,
|
|
# with possibility to enable incremental backups for versioning.
|
|
|
|
# TODO: systemd unit
|
|
# - [x] script taking configurable args
|
|
# - [x] sync from/to paths
|
|
# - [ ] support
|
|
# - [ ] nfs
|
|
# - [ ] sftp
|
|
# - [ ] ssh
|
|
# - [x] local
|
|
# - [x] rsyncd
|
|
# - [ ] retention limit for incremental backups
|
|
|
|
options.modules.services.rsync-backup = {
|
|
enable = mkEnableOption "rsync backups";
|
|
|
|
modules = mkOption {
|
|
default = [ ];
|
|
type = listOf (submoduleWith {
|
|
shorthandOnlyDefinesConfig = true;
|
|
modules = toList (import ./module.nix);
|
|
specialArgs = {
|
|
rootCfg = cfg;
|
|
};
|
|
});
|
|
};
|
|
|
|
exclude = mkOption {
|
|
type = listOf str;
|
|
default = [ ".git" ];
|
|
};
|
|
|
|
followGitignore = mkOption {
|
|
type = bool;
|
|
default = true;
|
|
};
|
|
|
|
package = mkOption {
|
|
type = package;
|
|
default = pkgs.rsync;
|
|
description = ''
|
|
The rsync package to use.
|
|
'';
|
|
};
|
|
|
|
interval = mkOption {
|
|
type = nonEmptyStr;
|
|
default = "daily";
|
|
};
|
|
|
|
unitName = mkOption {
|
|
type = nonEmptyStr;
|
|
default = "rsync-backup";
|
|
};
|
|
|
|
port = mkOption {
|
|
type = port;
|
|
default = options.modules.server.rsync-daemon.port.default;
|
|
};
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
systemd.timers = listToAttrs (
|
|
map (
|
|
mod:
|
|
let
|
|
name = "${cfg.unitName}-${slugify mod.target.location}";
|
|
in
|
|
{
|
|
inherit name;
|
|
value = {
|
|
enable = true;
|
|
wantedBy = [ "timers.target" ];
|
|
unitConfig = {
|
|
Description = "Triggers rsync-backups regularly.";
|
|
};
|
|
timerConfig = {
|
|
Unit = "${name}.service";
|
|
OnCalendar = mod.interval;
|
|
Persistent = true;
|
|
};
|
|
};
|
|
}
|
|
) cfg.modules
|
|
);
|
|
|
|
systemd.services = listToAttrs (
|
|
map (mod: {
|
|
name = "${cfg.unitName}-${slugify mod.target.location}";
|
|
value = {
|
|
script =
|
|
let
|
|
destination =
|
|
if mod.incremental.enable then "${mod.target.finalLocation}/backup" else mod.target.finalLocation;
|
|
sources = concatStringsSep " " (map (s: "\"${s}\"") mod.sources);
|
|
in
|
|
''
|
|
${cfg.package}/bin/rsync \
|
|
${mod.flagsFinal} \
|
|
${sources} \
|
|
"${destination}"
|
|
'';
|
|
|
|
requires = mkIf (mod.target.type == "rsyncd") [ "network.target" ];
|
|
unitConfig = {
|
|
Description = "Backs up files from a source location to a specified destination.";
|
|
};
|
|
|
|
postStop = ''
|
|
if [ "$SERVICE_RESULT" != "success" ]; then
|
|
${pkgs.curl}/bin/curl \
|
|
-H "Priority: urgent" \
|
|
-H "Title: Backup error" \
|
|
-d "Backup '${cfg.unitName}-${slugify mod.target.location}' had unexpected behaviour: $SERVICE_RESULT" \
|
|
https://ntfy.ccnlc.eu/rsync-backup
|
|
fi
|
|
'';
|
|
|
|
serviceConfig = {
|
|
Type = "simple";
|
|
Restart = "on-failure";
|
|
RestartSec = 300;
|
|
PrivateDevices = true;
|
|
PrivateTmp = true;
|
|
ProtectSystem = "full";
|
|
ReadOnlyPaths = concatStringsSep " " mod.sources;
|
|
IPAddressAllow = "any";
|
|
};
|
|
};
|
|
}) cfg.modules
|
|
);
|
|
};
|
|
}
|