|
1 | 1 | { |
2 | 2 | name = "zrepl"; |
3 | 3 |
|
4 | | - nodes.host = |
5 | | - { pkgs, ... }: |
6 | | - { |
7 | | - config = { |
8 | | - # Prerequisites for ZFS and tests. |
9 | | - boot.supportedFilesystems = [ "zfs" ]; |
10 | | - environment.systemPackages = [ pkgs.zrepl ]; |
11 | | - networking.hostId = "deadbeef"; |
12 | | - services.zrepl = { |
13 | | - enable = true; |
14 | | - settings = { |
15 | | - # Enable Prometheus output for status assertions. |
16 | | - global.monitoring = [ |
17 | | - { |
18 | | - type = "prometheus"; |
19 | | - listen = ":9811"; |
20 | | - } |
21 | | - ]; |
22 | | - # Create a periodic snapshot job for an ephemeral zpool. |
23 | | - jobs = [ |
24 | | - { |
25 | | - name = "snap_test"; |
26 | | - type = "snap"; |
27 | | - |
28 | | - filesystems."test" = true; |
29 | | - snapshotting = { |
30 | | - type = "periodic"; |
31 | | - prefix = "zrepl_"; |
32 | | - interval = "1s"; |
33 | | - }; |
34 | | - |
35 | | - pruning.keep = [ |
36 | | - { |
37 | | - type = "last_n"; |
38 | | - count = 8; |
39 | | - } |
40 | | - ]; |
41 | | - } |
42 | | - ]; |
| 4 | + nodes = { |
| 5 | + source = |
| 6 | + { nodes, pkgs, ... }: |
| 7 | + { |
| 8 | + config = { |
| 9 | + # Prerequisites for ZFS and tests. |
| 10 | + virtualisation.emptyDiskImages = [ |
| 11 | + 2048 |
| 12 | + ]; |
| 13 | + |
| 14 | + boot.supportedFilesystems = [ "zfs" ]; |
| 15 | + environment.systemPackages = [ |
| 16 | + pkgs.parted |
| 17 | + pkgs.zrepl |
| 18 | + ]; |
| 19 | + networking.firewall.allowedTCPPorts = [ 8888 ]; |
| 20 | + networking.hostId = "deadbeef"; |
| 21 | + services.zrepl = { |
| 22 | + enable = true; |
| 23 | + settings = { |
| 24 | + # Enable Prometheus output for status assertions. |
| 25 | + global.monitoring = [ |
| 26 | + { |
| 27 | + type = "prometheus"; |
| 28 | + listen = ":9811"; |
| 29 | + } |
| 30 | + ]; |
| 31 | + # Create a periodic snapshot job for an ephemeral zpool. |
| 32 | + jobs = [ |
| 33 | + { |
| 34 | + name = "snapshots"; |
| 35 | + type = "snap"; |
| 36 | + |
| 37 | + filesystems."tank/data" = true; |
| 38 | + snapshotting = { |
| 39 | + type = "periodic"; |
| 40 | + prefix = "zrepl_"; |
| 41 | + interval = "10s"; |
| 42 | + }; |
| 43 | + |
| 44 | + pruning.keep = [ |
| 45 | + { |
| 46 | + type = "last_n"; |
| 47 | + count = 8; |
| 48 | + } |
| 49 | + ]; |
| 50 | + } |
| 51 | + { |
| 52 | + name = "backup-target"; |
| 53 | + type = "source"; |
| 54 | + |
| 55 | + serve = { |
| 56 | + type = "tcp"; |
| 57 | + listen = ":8888"; |
| 58 | + |
| 59 | + clients = { |
| 60 | + "${nodes.target.networking.primaryIPAddress}" = "${nodes.target.networking.hostName}"; |
| 61 | + "${nodes.target.networking.primaryIPv6Address}" = "${nodes.target.networking.hostName}"; |
| 62 | + }; |
| 63 | + }; |
| 64 | + filesystems."tank/data" = true; |
| 65 | + # Snapshots are handled by the separate snap job |
| 66 | + snapshotting = { |
| 67 | + type = "manual"; |
| 68 | + }; |
| 69 | + } |
| 70 | + ]; |
| 71 | + }; |
43 | 72 | }; |
44 | 73 | }; |
45 | 74 | }; |
46 | | - }; |
| 75 | + |
| 76 | + target = |
| 77 | + { pkgs, ... }: |
| 78 | + { |
| 79 | + config = { |
| 80 | + # Prerequisites for ZFS and tests. |
| 81 | + virtualisation.emptyDiskImages = [ |
| 82 | + 2048 |
| 83 | + ]; |
| 84 | + |
| 85 | + boot.supportedFilesystems = [ "zfs" ]; |
| 86 | + environment.systemPackages = [ |
| 87 | + pkgs.parted |
| 88 | + pkgs.zrepl |
| 89 | + ]; |
| 90 | + networking.hostId = "deadd0d0"; |
| 91 | + services.zrepl = { |
| 92 | + enable = true; |
| 93 | + settings = { |
| 94 | + # Enable Prometheus output for status assertions. |
| 95 | + global.monitoring = [ |
| 96 | + { |
| 97 | + type = "prometheus"; |
| 98 | + listen = ":9811"; |
| 99 | + } |
| 100 | + ]; |
| 101 | + jobs = [ |
| 102 | + { |
| 103 | + name = "source-pull"; |
| 104 | + type = "pull"; |
| 105 | + |
| 106 | + connect = { |
| 107 | + type = "tcp"; |
| 108 | + address = "source:8888"; |
| 109 | + }; |
| 110 | + root_fs = "tank/zrepl/source"; |
| 111 | + interval = "15s"; |
| 112 | + recv = { |
| 113 | + placeholder = { |
| 114 | + encryption = "off"; |
| 115 | + }; |
| 116 | + }; |
| 117 | + pruning = { |
| 118 | + keep_sender = [ |
| 119 | + { |
| 120 | + type = "regex"; |
| 121 | + regex = ".*"; |
| 122 | + } |
| 123 | + ]; |
| 124 | + keep_receiver = [ |
| 125 | + { |
| 126 | + type = "grid"; |
| 127 | + grid = "1x1h(keep=all) | 24x1h"; |
| 128 | + regex = "^zrepl_"; |
| 129 | + } |
| 130 | + ]; |
| 131 | + }; |
| 132 | + } |
| 133 | + ]; |
| 134 | + }; |
| 135 | + }; |
| 136 | + }; |
| 137 | + }; |
| 138 | + }; |
47 | 139 |
|
48 | 140 | testScript = '' |
49 | 141 | start_all() |
50 | 142 |
|
51 | 143 | with subtest("Wait for zrepl and network ready"): |
52 | | - host.systemctl("start network-online.target") |
53 | | - host.wait_for_unit("network-online.target") |
54 | | - host.wait_for_unit("zrepl.service") |
| 144 | + for machine in source, target: |
| 145 | + machine.systemctl("start network-online.target") |
| 146 | + machine.wait_for_unit("network-online.target") |
| 147 | + machine.wait_for_unit("zrepl.service") |
| 148 | +
|
| 149 | + with subtest("Create tank zpool"): |
| 150 | + for machine in source, target: |
| 151 | + machine.succeed( |
| 152 | + "parted --script /dev/vdb mklabel gpt", |
| 153 | + "zpool create tank /dev/vdb", |
| 154 | + ) |
55 | 155 |
|
56 | | - with subtest("Create test zpool"): |
57 | | - # ZFS requires 64MiB minimum pool size. |
58 | | - host.succeed("fallocate -l 64MiB /root/zpool.img") |
59 | | - host.succeed("zpool create test /root/zpool.img") |
| 156 | + # Create ZFS datasets |
| 157 | + source.succeed("zfs create tank/data") |
| 158 | + target.succeed("zfs create -p tank/zrepl/source") |
60 | 159 |
|
61 | | - with subtest("Check for completed zrepl snapshot"): |
| 160 | + with subtest("Check for completed zrepl snapshot on target"): |
62 | 161 | # zrepl periodic snapshot job creates a snapshot with this prefix. |
63 | | - host.wait_until_succeeds("zfs list -t snapshot | grep -q zrepl_") |
| 162 | + target.wait_until_succeeds("zfs list -t snapshot | grep -q tank/zrepl/source/tank/data@zrepl_") |
| 163 | +
|
| 164 | + with subtest("Check for completed zrepl bookmark on source"): |
| 165 | + source.wait_until_succeeds("zfs list -t bookmark | grep -q tank/data#zrepl_") |
64 | 166 |
|
65 | 167 | with subtest("Verify HTTP monitoring server is configured"): |
66 | | - out = host.succeed("curl -f localhost:9811/metrics") |
| 168 | + out = source.succeed("curl -f localhost:9811/metrics") |
67 | 169 |
|
68 | 170 | assert ( |
69 | 171 | "zrepl_start_time" in out |
70 | 172 | ), "zrepl start time metric was not found in Prometheus output" |
71 | 173 |
|
72 | 174 | assert ( |
73 | | - "zrepl_zfs_snapshot_duration_count{filesystem=\"test\"}" in out |
74 | | - ), "zrepl snapshot counter for test was not found in Prometheus output" |
| 175 | + "zrepl_zfs_snapshot_duration_count{filesystem=\"tank/data\"}" in out |
| 176 | + ), "zrepl snapshot counter for tank/data was not found in Prometheus output" |
75 | 177 | ''; |
76 | 178 | } |
0 commit comments