nixos-config/modules/home-manager/services/borgmatic.nix

234 lines
6.6 KiB
Nix
Raw Normal View History

# A re-implementation of the Borgmatic service home-manager module. The
# reimplementation basically separates all of the configurations instead of a
# oneshot where it will execute Borgmatic with all present configurations
# (which is fine but too overwhelming for my taste).
#
# It has an added integration for individual Borgmatic configurations from
# `programs.borgmatic.backups` (also a reimplemented version from the upstream)
# to be added to the jobset and has more control over each service unit.
#
# As a design constraint, you should still be able to do what the upstream
# service module with a little bit of elbow grease.
{ config, lib, pkgs, ... }:
let
cfg = config.services.borgmatic;
programCfg = config.programs.borgmatic;
settingsFormat = pkgs.formats.yaml { };
borgmaticProgramModule = { name, lib, ... }: {
options = {
initService = {
enable = lib.mkEnableOption "include this particular backup as part of Borgmatic jobset at {option}`services.borgmatic.jobs`";
startAt = lib.mkOption {
type = lib.types.nonEmptyStr;
description = ''
Indicates how often the associated service occurs. Accepts value as
found from {manpage}`systemd.time(7)`.
'';
default = "daily";
example = "04:30";
};
};
};
};
borgmaticJobModule = { config, lib, name, ... }: let
settingsFile = settingsFormat.generate "borgmatic-job-config-${name}" config.settings;
in {
options = {
settings = lib.mkOption {
type = settingsFormat.type;
description = ''
Configuration settings associated with the job. If this is set, the
generated output is added as an additional argument (i.e., `--config
SETTINGSFILE`) in the service script.
'';
default = { };
example = lib.literalExpression ''
{
source_directories = [
config.xdg.userDirs.document
config.xdg.userDirs.download
config.xdg.userDirs.music
config.xdg.userDirs.video
];
keep_daily = 5;
keep_weekly = 10;
keep_monthly = 20;
repositories = lib.singleton {
path = "ssh://asodajdoiasjdoij";
label = "remote";
};
}
'';
};
startAt = lib.mkOption {
type = lib.types.nonEmptyStr;
description = ''
Indicates how often backup will occur. This is to be used as value
for `Timer.OnCalendar=` in the systemd unit. See
{manpage}`systemd.time(7)` for more details.
'';
default = "daily";
example = "04:30";
};
extraArgs = lib.mkOption {
type = with lib.types; listOf str;
description = ''
List of arguments to be passed to the Borgmatic backup service.
'';
default = [ ];
example = lib.literalExpression ''
[
"--stats"
"--verbosity" "1"
"--syslog-verbosity" "1"
"--list"
]
'';
};
};
config = {
extraArgs = lib.mkMerge [
cfg.extraArgs
(lib.optionals (config.settings != {}) (
lib.mkBefore [
"--config" settingsFile
]
))
];
};
};
formatUnitName = name: "borgmatic-job-${name}";
mkBorgmaticServiceUnit = n: v:
lib.nameValuePair (formatUnitName n) {
Unit = {
Description = "Borgmatic backup job '${n}'";
Documentation = [
"https://torsion.org/borgmatic/docs/reference/configuration"
];
ConditionACPower = true;
};
Service = {
# TODO: Just cargo-culted from the upstream home-manager module. Will
# need more info on this.
Nice = 19;
IOSchedulingClass = "best-effort";
IOSchedulingPriority = 7;
IOWeight = 100;
Restart = "on-failure";
LogRateLimitIntervalSec = 0;
ExecStart = ''
${lib.getExe' cfg.package "borgmatic"} ${lib.concatStringsSep " " v.extraArgs}
'';
PrivateTmp = true;
};
};
mkBorgmaticTimerUnit = n: v:
lib.nameValuePair (formatUnitName n) {
Unit.Description = "Borgmatic backup job '${n}'";
Timer = {
OnCalendar = v.startAt;
Persistent = lib.mkDefault true;
RandomizedDelaySec = lib.mkDefault "10m";
};
Install.WantedBy = [ "timers.target" ];
};
mkBorgmaticServiceFromConfig = n: v:
lib.nameValuePair "borgmatic-config-${n}" {
inherit (v.initService) startAt;
extraArgs = [
"--config" "${config.xdg.configHome}/borgmatic.d/${n}.yaml"
];
};
in
{
disabledModules = [ "services/borgmatic.nix" ];
options.programs.borgmatic.backups = lib.mkOption {
type = with lib.types; attrsOf (submodule borgmaticProgramModule);
};
options.services.borgmatic = {
package = lib.mkPackageOption pkgs "borgmatic" { };
extraArgs = lib.mkOption {
type = with lib.types; listOf str;
description = ''
Global list of additional arguments for all of the jobs.
'';
default = [ ];
example = [
"--stats"
"--verbosity" "1"
];
};
jobs = lib.mkOption {
type = with lib.types; attrsOf (submodule borgmaticJobModule);
default = { };
example = lib.literalExpression ''
{
personal = {
startAt = "05:30";
settings = {
source_directories = [
"''${config.xdg.configHome}"
"''${config.xdg.userDirs.extraConfig.XDG_PROJECTS_DIR}"
"''${config.home.homeDirectory}/.thunderbird"
"''${config.home.homeDirectory}/Zotero"
];
repositories = [
{
path = "ssh://k8pDxu32@k8pDxu32.repo.borgbase.com/./repo";
label = "borgbase";
}
{
path = "/var/lib/backups/local.borg";
label = "local";
}
];
keep_daily = 7;
keep_weekly = 4;
keep_monthly = 6;
};
};
}
'';
};
};
config = {
systemd.user.services =
lib.mapAttrs' mkBorgmaticServiceUnit cfg.jobs;
systemd.user.timers =
lib.mapAttrs' mkBorgmaticTimerUnit cfg.jobs;
services.borgmatic.jobs =
let
validService = lib.filterAttrs (n: v: v.initService.enable) programCfg.backups;
in
lib.mapAttrs' mkBorgmaticServiceFromConfig validService;
};
}