85 lines
2.4 KiB
Nix
85 lines
2.4 KiB
Nix
# SPDX-FileCopyrightText: 2024 Simon Bruder <simon@sbruder.de>
|
||
#
|
||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||
|
||
{ config, lib, pkgs, ... }:
|
||
let
|
||
cfg = config.sbruder.restic.backups.vm-image;
|
||
in
|
||
{
|
||
options.sbruder.restic.backups.vm-image = {
|
||
enable = lib.mkEnableOption "restic vm image backup";
|
||
timerConfig = lib.mkOption {
|
||
type = with lib.types; attrsOf str;
|
||
default = {
|
||
OnCalendar = "03:00";
|
||
RandomizedDelaySec = "3h";
|
||
};
|
||
};
|
||
lvm = {
|
||
vg = lib.mkOption {
|
||
type = lib.types.str;
|
||
default = "${config.networking.hostName}-vg";
|
||
};
|
||
lvs = lib.mkOption {
|
||
type = with lib.types; listOf str;
|
||
default = [ ];
|
||
};
|
||
};
|
||
};
|
||
|
||
config = lib.mkIf cfg.enable {
|
||
systemd.services = lib.listToAttrs (map
|
||
(lv: lib.nameValuePair "restic-backups-vm-image-${lv}" {
|
||
wants = [ "network-online.target" ];
|
||
after = [ "network-online.target" ];
|
||
restartIfChanged = false;
|
||
|
||
path = with pkgs; [ lvm2 restic ];
|
||
|
||
script = ''
|
||
set -euo pipefail
|
||
|
||
LV_NAME=${lib.escapeShellArg lv}
|
||
FULL_LV_NAME=${lib.escapeShellArg cfg.lvm.vg}/"$LV_NAME"
|
||
SNAPSHOT_LV_NAME="restic-snapshot-$LV_NAME"
|
||
FULL_SNAPSHOT_LV_NAME=${lib.escapeShellArg cfg.lvm.vg}/"$SNAPSHOT_LV_NAME"
|
||
|
||
lvcreate --name "$SNAPSHOT_LV_NAME" --snapshot "$FULL_LV_NAME" --permission r --ignoreactivationskip
|
||
|
||
function cleanup {
|
||
lvchange --activate n "$FULL_SNAPSHOT_LV_NAME"
|
||
lvremove "$FULL_SNAPSHOT_LV_NAME"
|
||
}
|
||
trap cleanup EXIT INT TERM
|
||
|
||
restic backup \
|
||
--tag vm-image \
|
||
--host ${config.networking.hostName}-hypervisor \
|
||
--verbose \
|
||
--stdin \
|
||
--stdin-filename "$LV_NAME" \
|
||
< "/dev/$FULL_SNAPSHOT_LV_NAME"
|
||
'';
|
||
|
||
environment = {
|
||
RESTIC_CACHE_DIR = "/var/cache/restic-backups-system"; # hack: reuse system backup’s directory
|
||
RESTIC_REPOSITORY_FILE = config.sops.secrets.restic-repository.path;
|
||
RESTIC_PASSWORD_FILE = config.sops.secrets.restic-password.path;
|
||
};
|
||
|
||
serviceConfig = {
|
||
Type = "oneshot";
|
||
};
|
||
})
|
||
cfg.lvm.lvs);
|
||
|
||
systemd.timers = (lib.listToAttrs (map
|
||
(lv: lib.nameValuePair "restic-backups-vm-image-${lv}" {
|
||
wantedBy = [ "timers.target" ];
|
||
inherit (cfg) timerConfig;
|
||
})
|
||
cfg.lvm.lvs));
|
||
};
|
||
}
|