diff --git a/hosts/yodaNas/btrbk-config.nix b/hosts/yodaNas/btrbk-config.nix new file mode 100644 index 0000000..4cb67f6 --- /dev/null +++ b/hosts/yodaNas/btrbk-config.nix @@ -0,0 +1,54 @@ +{ config, pkgs, ... }: +let + ssd-subvolumes = { + "arch.p1st.de" = {}; + "blogger.privacy1st.de" = {}; + "changedetection.p1st.de" = {}; + "cloud.privacy1st.de" = {}; + "git.privacy1st.de" = {}; + "mastodon-toot-follower.privacy1st.de" = {}; + "money.p1st.de" = {}; + "music.privacy1st.de" = {}; + "paste.p1st.de" = {}; + "proxy" = {}; + "recipe.privacy1st.de" = {}; + "traggo.privacy1st.de" = {}; + }; + hdd-subvolumes = { + "cloud.privacy1st.de" = {}; + # MediaKollektiv: 796 GiB + "cloud.media-kollektiv.eu" = {}; + }; +in +{ + yoda.btrbkSnapshots = [ + { + instance = "local-snapshot-ssd"; + volume = "/jc-data"; + snapshot_dir = "/snap"; + subvolume = ssd-subvolumes; + } + { + instance = "local-snapshot-hdd"; + volume = "/mnt/data/jc-data"; + snapshot_dir = "/mnt/data/snap2"; + subvolume = hdd-subvolumes; + } + ]; + yoda.btrbkBackups = [ + { + instance = "local-backup-ssd"; + volume = "/jc-data"; + snapshot_dir = "/snap"; + target = "/mnt/backup/snap"; + subvolume = ssd-subvolumes; + } + { + instance = "local-backup-hdd"; + volume = "/mnt/data/jc-data"; + snapshot_dir = "/mnt/data/snap2"; + target = "/mnt/backup/snap2"; + subvolume = hdd-subvolumes; + } + ]; +} diff --git a/hosts/yodaNas/configuration.nix b/hosts/yodaNas/configuration.nix index ee5a065..db71ad7 100644 --- a/hosts/yodaNas/configuration.nix +++ b/hosts/yodaNas/configuration.nix @@ -23,6 +23,7 @@ ../../modules/journalwatch.nix ../../modules/btrbk + ./btrbk-config.nix ../../modules/netcup-dns.nix ../../modules/de-p1st-monitor.nix ../../modules/spin-down.nix diff --git a/modules/btrbk/backup.nix b/modules/btrbk/backup.nix new file mode 100644 index 0000000..1c4f026 --- /dev/null +++ b/modules/btrbk/backup.nix @@ -0,0 +1,73 @@ +{ lib, config, options, pkgs, modulesPath, ... }: +with lib; +let + cfg = config.yoda.btrbkBackups; + daily = { + preserve-min = "no"; + preserve = "7d 4w 6m"; + }; +in +{ + options = { + yoda.btrbkBackups = mkOption { + type = types.listOf types.attrs; + default = []; + example = [{ + # Optional. + # If this is `true` and `volume` starts with `ssh://`, `lz4` transport compression is enabled. + lz4 = true; + instance = "local-backup-ssd"; + volume = "/jc-data"; + snapshot_dir = "/snap"; + target = "/mnt/backup/snap"; + subvolume = { + "arch.p1st.de" = {}; + }; + }]; + description = '' + List containing attrsets. + Each attrset is used to create one btrbk instance. + ''; + }; + }; + + # lib.forEach: + # https://github.com/NixOS/nixpkgs/blob/54f00576aa6139a9d54062d0edc2fb31423f0ffb/lib/lists.nix#L36 + # lib.attrsets.mergeAttrsList: + # https://github.com/NixOS/nixpkgs/blob/54f00576aa6139a9d54062d0edc2fb31423f0ffb/lib/attrsets.nix#L786 + config = { + services.btrbk.instances = + # Merge list of attr sets into one attr set. + attrsets.mergeAttrsList ( + forEach + cfg + (x: + # `services.btrbk.instances` template. + { + "${x.instance}" = { + #onCalendar = null; + onCalendar = "00:05"; + settings = { + timestamp_format = "long"; + stream_compress = mkIf ((x.lz4 or false) && strings.hasPrefix "ssh://" x.volume) "lz4"; + + # Create backups. + target_preserve_min = daily.preserve-min; + target_preserve = daily.preserve; + + # Don't create or delete snapshots. + snapshot_preserve_min = "all"; + snapshot_create = "no"; + + volume."${x.volume}" = { + snapshot_dir = x.snapshot_dir; + target = x.target; + subvolume = x.subvolume; + }; + }; + }; + } + ) + ); + }; +} diff --git a/modules/btrbk/default.nix b/modules/btrbk/default.nix index 00b5c04..18c3b63 100644 --- a/modules/btrbk/default.nix +++ b/modules/btrbk/default.nix @@ -11,88 +11,18 @@ # #=> ExecStart=/nix/store/53nvbl1c0w14524j7v3fpn9py31yi2hb-btrbk-0.32.6/bin/btrbk -c /etc/btrbk/local-backup.conf run { config, pkgs, ... }: -let - ssd-subvolumes = { - "arch.p1st.de" = {}; - "blogger.privacy1st.de" = {}; - "changedetection.p1st.de" = {}; - "cloud.privacy1st.de" = {}; - "git.privacy1st.de" = {}; - "mastodon-toot-follower.privacy1st.de" = {}; - "money.p1st.de" = {}; - "music.privacy1st.de" = {}; - "paste.p1st.de" = {}; - "proxy" = {}; - "recipe.privacy1st.de" = {}; - "traggo.privacy1st.de" = {}; - }; - hdd-subvolumes = { - "cloud.privacy1st.de" = {}; - # MediaKollektiv: 796 GiB - "cloud.media-kollektiv.eu" = {}; - }; - preserve-hourly = "24h 7d 4w 6m"; - preserve-daily = "7d 4w 6m"; -in { + imports = [ + ./snapshot.nix + ./backup.nix + ]; + services.btrbk = { + # Transport compression with `lz4`, + # see `./backup.nix`. extraPackages = [ pkgs.lz4 ]; # Lowest scheduling priority. niceness = 19; - # Set of btrbk instances. The instance named btrbk is the default one. - instances = { - - "local-snapshot" = { - onCalendar = "hourly"; - #onCalendar = "*:0/15"; # Every 15min - - settings = { - timestamp_format = "long"; - #stream_compress = "lz4"; - - snapshot_preserve_min = "2d"; - snapshot_preserve = preserve-hourly; - - volume."/jc-data" = { - snapshot_dir = "/snap"; - subvolume = ssd-subvolumes; - }; - volume."/mnt/data/jc-data" = { - snapshot_dir = "/mnt/data/snap2"; - subvolume = hdd-subvolumes; - }; - }; - }; - - "local-backup" = { - # Run daily, 5 minutes after `local-snapshot` 0'o'clock timer. - onCalendar = "00:05"; - - settings = { - timestamp_format = "long"; - #stream_compress = "lz4"; - - # Create backups. - target_preserve_min = "no"; - target_preserve = preserve-daily; - - # Don't create or delete snapshots. - snapshot_preserve_min = "all"; - snapshot_create = "no"; - - volume."/jc-data" = { - snapshot_dir = "/snap"; - target = "/mnt/backup/snap"; - subvolume = ssd-subvolumes; - }; - volume."/mnt/data/jc-data" = { - snapshot_dir = "/mnt/data/snap2"; - target = "/mnt/backup/snap2"; - subvolume = hdd-subvolumes; - }; - }; - }; - - }; + # The `instances` option is set by `./snapshot.nix` and `./backup.nix`. }; } diff --git a/modules/btrbk/snapshot.nix b/modules/btrbk/snapshot.nix new file mode 100644 index 0000000..79c4479 --- /dev/null +++ b/modules/btrbk/snapshot.nix @@ -0,0 +1,62 @@ +{ lib, config, options, pkgs, modulesPath, ... }: +with lib; +let + cfg = config.yoda.btrbkSnapshots; + hourly = { + preserve-min = "2d"; + preserve = "24h 7d 4w 6m"; + }; +in +{ + options = { + yoda.btrbkSnapshots = mkOption { + type = types.listOf types.attrs; + default = []; + example = [{ + instance = "local-snapshot-ssd"; + volume = "/jc-data"; + snapshot_dir = "/snap"; + subvolume = { + "arch.p1st.de" = {}; + }; + }]; + description = '' + List containing attrsets. + Each attrset is used to create one btrbk instance. + ''; + }; + }; + + # lib.forEach: + # https://github.com/NixOS/nixpkgs/blob/54f00576aa6139a9d54062d0edc2fb31423f0ffb/lib/lists.nix#L36 + # lib.attrsets.mergeAttrsList: + # https://github.com/NixOS/nixpkgs/blob/54f00576aa6139a9d54062d0edc2fb31423f0ffb/lib/attrsets.nix#L786 + config = { + services.btrbk.instances = + # Merge list of attr sets into one attr set. + attrsets.mergeAttrsList ( + forEach + cfg + (x: + # `services.btrbk.instances` template. + { + "${x.instance}" = { + #onCalendar = null; + onCalendar = "hourly"; + settings = { + timestamp_format = "long"; + + snapshot_preserve_min = hourly.preserve-min; + snapshot_preserve = hourly.preserve; + + volume."${x.volume}" = { + snapshot_dir = x.snapshot_dir; + subvolume = x.subvolume; + }; + }; + }; + } + ) + ); + }; +}