main
1{
2 den,
3 lib,
4 ...
5}: {
6 den.aspects.core.impermanence.btrfs = {
7 settings = {
8 partId = lib.mkOption {
9 type = lib.types.str;
10 default = "";
11 description = ''
12 Disk part id (e.g., "/dev/disk/by-partuuid/...").
13 If not set, auto-detect when aspects.disk.disko is included.
14 '';
15 };
16 preserveTime = lib.mkOption {
17 type = lib.types.ints.positive;
18 default = 30;
19 description = ''
20 Time old root/home subvolumes preserved.
21 '';
22 };
23 };
24
25 nixos = {host, ...}: let
26 cfg = host.settings.core.impermanence.btrfs;
27
28 partDevice =
29 if cfg.partId != ""
30 then
31 if lib.hasPrefix "/dev/" cfg.partId
32 then cfg.partId
33 else "/dev/disk/by-partuuid/" + cfg.partId
34 else if (host.hasAspect den.aspects.disk.disko)
35 then "/dev/disk/by-partlabel/disk-main-nixos"
36 else abort "Host not included disk.disko aspect, Please set settings.core.impermanence.btrfs.partId.";
37
38 partDeviceUnit =
39 lib.removePrefix "-" (
40 lib.replaceStrings ["-" "/"] ["\\x2d" "-"] partDevice
41 )
42 + ".device";
43
44 script = subvol: ''
45 mkdir -p /mnt
46
47 mount ${partDevice} /mnt
48
49 mkdir -p /mnt/${subvol}_old
50 timestamp=$(date "+%Y-%m-%-d_%H:%M:%S")
51 rm -rf "/mnt/${subvol}_old/$timestamp"
52 mv /mnt/${subvol} /mnt/${subvol}_old/$timestamp
53
54 delete_subvolume_recursively() {
55 IFS=$'\n'
56 for i in $(btrfs subvolume list -o "$1" | cut -f 9- -d ' '); do
57 delete_subvolume_recursively "/mnt/$i"
58 done
59 btrfs subvolume delete "$1"
60 }
61
62 for i in $(find /mnt/${subvol}_old -maxdepth 1 -mtime +${toString cfg.preserveTime}); do
63 delete_subvolume_recursively "$i"
64 done
65
66 btrfs subvolume create /mnt/${subvol}
67 umount /mnt
68 '';
69 in {
70 boot.initrd.systemd.services = lib.mkIf (host.hasAspect den.aspects.disk.btrfs) {
71 rollback-btrfs-root = {
72 description = "Rollback and clean old btrfs root subvolumes";
73 wantedBy = ["initrd.target"];
74 before = ["sysroot.mount"];
75 after = [partDeviceUnit];
76 requires = [partDeviceUnit];
77 unitConfig.DefaultDependencies = false;
78 serviceConfig.Type = "oneshot";
79 script = script "root";
80 };
81 rollback-btrfs-home = {
82 description = "Rollback and clean old btrfs home subvolumes";
83 wantedBy = ["initrd.target"];
84 before = ["home.mount"];
85 after = [partDeviceUnit];
86 requires = [partDeviceUnit];
87 unitConfig.DefaultDependencies = false;
88 serviceConfig.Type = "oneshot";
89 script = script "home";
90 };
91 };
92 };
93 };
94}