1{ pkgs, ... }:
2let
3 inherit (import ./ssh-keys.nix pkgs)
4 snakeOilPrivateKey
5 snakeOilPublicKey
6 ;
7
8 commonConfig =
9 { pkgs, ... }:
10 {
11 virtualisation.emptyDiskImages = [ 2048 ];
12 boot.supportedFilesystems = [ "zfs" ];
13 environment.systemPackages = [ pkgs.parted ];
14 };
15in
16{
17 name = "sanoid";
18 meta = with pkgs.lib.maintainers; {
19 maintainers = [ lopsided98 ];
20 };
21
22 nodes = {
23 source =
24 { ... }:
25 {
26 imports = [ commonConfig ];
27 networking.hostId = "daa82e91";
28
29 programs.ssh.extraConfig = ''
30 UserKnownHostsFile=/dev/null
31 StrictHostKeyChecking=no
32 '';
33
34 services.sanoid = {
35 enable = true;
36 templates.test = {
37 hourly = 12;
38 daily = 1;
39 monthly = 1;
40 yearly = 1;
41
42 autosnap = true;
43 };
44 datasets."pool/sanoid".use_template = [ "test" ];
45 datasets."pool/compat".useTemplate = [ "test" ];
46 extraArgs = [ "--verbose" ];
47 };
48
49 services.syncoid = {
50 enable = true;
51 sshKey = "/var/lib/syncoid/id_ecdsa";
52 commands = {
53 # Sync snapshot taken by sanoid
54 "pool/sanoid" = {
55 target = "root@target:pool/sanoid";
56 extraArgs = [
57 "--no-sync-snap"
58 "--create-bookmark"
59 ];
60 };
61 # Take snapshot and sync
62 "pool/syncoid".target = "root@target:pool/syncoid";
63
64 # Test pool without parent (regression test for https://github.com/NixOS/nixpkgs/pull/180111)
65 "pool".target = "root@target:pool/full-pool";
66
67 # Test backward compatible options (regression test for https://github.com/NixOS/nixpkgs/issues/181561)
68 "pool/compat" = {
69 target = "root@target:pool/compat";
70 extraArgs = [ "--no-sync-snap" ];
71 };
72 };
73 };
74 };
75 target =
76 { ... }:
77 {
78 imports = [ commonConfig ];
79 networking.hostId = "dcf39d36";
80
81 services.openssh.enable = true;
82 users.users.root.openssh.authorizedKeys.keys = [ snakeOilPublicKey ];
83 };
84 };
85
86 testScript = ''
87 source.succeed(
88 "mkdir /mnt",
89 "parted --script /dev/vdb -- mklabel msdos mkpart primary 1024M -1s",
90 "udevadm settle",
91 "zpool create pool -R /mnt /dev/vdb1",
92 "zfs create pool/sanoid",
93 "zfs create pool/compat",
94 "zfs create pool/syncoid",
95 "udevadm settle",
96 )
97 target.succeed(
98 "mkdir /mnt",
99 "parted --script /dev/vdb -- mklabel msdos mkpart primary 1024M -1s",
100 "udevadm settle",
101 "zpool create pool -R /mnt /dev/vdb1",
102 "udevadm settle",
103 )
104
105 source.succeed(
106 "mkdir -m 700 -p /var/lib/syncoid",
107 "cat '${snakeOilPrivateKey}' > /var/lib/syncoid/id_ecdsa",
108 "chmod 600 /var/lib/syncoid/id_ecdsa",
109 "chown -R syncoid:syncoid /var/lib/syncoid/",
110 )
111
112 assert len(source.succeed("zfs allow pool")) == 0, "Pool shouldn't have delegated permissions set before snapshotting"
113 assert len(source.succeed("zfs allow pool/sanoid")) == 0, "Sanoid dataset shouldn't have delegated permissions set before snapshotting"
114 assert len(source.succeed("zfs allow pool/syncoid")) == 0, "Syncoid dataset shouldn't have delegated permissions set before snapshotting"
115
116 # Take snapshot with sanoid
117 source.succeed("touch /mnt/pool/sanoid/test.txt")
118 source.succeed("touch /mnt/pool/compat/test.txt")
119 source.systemctl("start --wait sanoid.service")
120
121 assert len(source.succeed("zfs allow pool")) == 0, "Pool shouldn't have delegated permissions set after snapshotting"
122 assert len(source.succeed("zfs allow pool/sanoid")) == 0, "Sanoid dataset shouldn't have delegated permissions set after snapshotting"
123 assert len(source.succeed("zfs allow pool/syncoid")) == 0, "Syncoid dataset shouldn't have delegated permissions set after snapshotting"
124
125 # Sync snapshots
126 target.wait_for_open_port(22)
127 source.succeed("touch /mnt/pool/syncoid/test.txt")
128 source.systemctl("start --wait syncoid-pool-sanoid.service")
129 target.succeed("cat /mnt/pool/sanoid/test.txt")
130 source.systemctl("start --wait syncoid-pool-syncoid.service")
131 source.systemctl("start --wait syncoid-pool-syncoid.service")
132 target.succeed("cat /mnt/pool/syncoid/test.txt")
133
134 assert(len(source.succeed("zfs list -H -t snapshot pool/syncoid").splitlines()) == 1), "Syncoid should only retain one sync snapshot"
135
136 source.systemctl("start --wait syncoid-pool.service")
137 target.succeed("[[ -d /mnt/pool/full-pool/syncoid ]]")
138
139 source.systemctl("start --wait syncoid-pool-compat.service")
140 target.succeed("cat /mnt/pool/compat/test.txt")
141
142 assert len(source.succeed("zfs allow pool")) == 0, "Pool shouldn't have delegated permissions set after syncing snapshots"
143 assert len(source.succeed("zfs allow pool/sanoid")) == 0, "Sanoid dataset shouldn't have delegated permissions set after syncing snapshots"
144 assert len(source.succeed("zfs allow pool/syncoid")) == 0, "Syncoid dataset shouldn't have delegated permissions set after syncing snapshots"
145 '';
146}