restic/vm-image: Init
This commit is contained in:
parent
0fa4e6d855
commit
5693e6b75d
|
@ -24,6 +24,16 @@ let
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
sbruder.restic = {
|
||||||
|
enable = true;
|
||||||
|
backups.vm-image = {
|
||||||
|
enable = true;
|
||||||
|
lvm.lvs = [
|
||||||
|
"hiroshi"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
virtualisation.libvirtd = {
|
virtualisation.libvirtd = {
|
||||||
enable = true;
|
enable = true;
|
||||||
qemu.package = pkgs.qemu_kvm;
|
qemu.package = pkgs.qemu_kvm;
|
||||||
|
|
|
@ -10,7 +10,7 @@ let
|
||||||
sftpPort = 23;
|
sftpPort = 23;
|
||||||
repository = "sftp://${sftpTarget}:${toString sftpPort}/personal";
|
repository = "sftp://${sftpTarget}:${toString sftpPort}/personal";
|
||||||
|
|
||||||
mkPruneConfig = { tag, timerConfig }: {
|
mkPruneConfig = { tag, timerConfig, opts }: {
|
||||||
inherit repository timerConfig;
|
inherit repository timerConfig;
|
||||||
passwordFile = config.sops.secrets.restic-password.path;
|
passwordFile = config.sops.secrets.restic-password.path;
|
||||||
paths = [ ];
|
paths = [ ];
|
||||||
|
@ -20,18 +20,15 @@ let
|
||||||
];
|
];
|
||||||
pruneOpts = [
|
pruneOpts = [
|
||||||
"--compression auto"
|
"--compression auto"
|
||||||
"--keep-daily 7"
|
|
||||||
"--keep-monthly 12"
|
|
||||||
"--keep-weekly 5"
|
|
||||||
"--keep-yearly 10"
|
|
||||||
"--tag ${tag}"
|
"--tag ${tag}"
|
||||||
"--verbose"
|
"--verbose"
|
||||||
];
|
] ++ opts;
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./system.nix
|
./system.nix
|
||||||
|
./vm-image.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
options.sbruder.restic = {
|
options.sbruder.restic = {
|
||||||
|
@ -71,6 +68,23 @@ in
|
||||||
OnCalendar = "*-1/2-07 03:00:00";
|
OnCalendar = "*-1/2-07 03:00:00";
|
||||||
RandomizedDelaySec = "4h";
|
RandomizedDelaySec = "4h";
|
||||||
};
|
};
|
||||||
|
opts = [
|
||||||
|
"--keep-daily 7"
|
||||||
|
"--keep-monthly 12"
|
||||||
|
"--keep-weekly 5"
|
||||||
|
"--keep-yearly 10"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
vm-image-prune = mkPruneConfig {
|
||||||
|
tag = "vm-image";
|
||||||
|
timerConfig = {
|
||||||
|
OnCalendar = "06:00";
|
||||||
|
RandomizedDelaySec = "1h";
|
||||||
|
};
|
||||||
|
opts = [
|
||||||
|
"--keep-last 1"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
84
modules/restic/vm-image.nix
Normal file
84
modules/restic/vm-image.nix
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
# 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));
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue