diff --git a/nixos/modules/services/backup/zrepl.nix b/nixos/modules/services/backup/zrepl.nix index 4356479b6635..73f5e4d9f6d7 100644 --- a/nixos/modules/services/backup/zrepl.nix +++ b/nixos/modules/services/backup/zrepl.nix @@ -38,6 +38,9 @@ in environment.etc."zrepl/zrepl.yml".source = configFile; systemd.packages = [ pkgs.zrepl ]; + + # Note that pkgs.zrepl copies and adapts the upstream systemd unit, and + # the fields defined here only override certain fields from that unit. systemd.services.zrepl = { requires = [ "local-fs.target" ]; wantedBy = [ "zfs.target" ]; diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index ab6906cd24e2..cb6089983f8c 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -590,5 +590,6 @@ in zigbee2mqtt = handleTest ./zigbee2mqtt.nix {}; zoneminder = handleTest ./zoneminder.nix {}; zookeeper = handleTest ./zookeeper.nix {}; + zrepl = handleTest ./zrepl.nix {}; zsh-history = handleTest ./zsh-history.nix {}; } diff --git a/nixos/tests/zrepl.nix b/nixos/tests/zrepl.nix new file mode 100644 index 000000000000..85dd834a6aaf --- /dev/null +++ b/nixos/tests/zrepl.nix @@ -0,0 +1,66 @@ +import ./make-test-python.nix ( + { + nodes.host = {config, pkgs, ...}: { + config = { + # Prerequisites for ZFS and tests. + boot.supportedFilesystems = [ "zfs" ]; + environment.systemPackages = [ pkgs.zrepl ]; + networking.hostId = "deadbeef"; + services.zrepl = { + enable = true; + settings = { + # Enable Prometheus output for status assertions. + global.monitoring = [{ + type = "prometheus"; + listen = ":9811"; + }]; + # Create a periodic snapshot job for an ephemeral zpool. + jobs = [{ + name = "snap_test"; + type = "snap"; + + filesystems."test" = true; + snapshotting = { + type = "periodic"; + prefix = "zrepl_"; + interval = "1s"; + }; + + pruning.keep = [{ + type = "last_n"; + count = 8; + }]; + }]; + }; + }; + }; + }; + + testScript = '' + start_all() + + with subtest("Wait for zrepl and network ready"): + host.wait_for_unit("network-online.target") + host.wait_for_unit("zrepl.service") + + with subtest("Create test zpool"): + # ZFS requires 64MiB minimum pool size. + host.succeed("fallocate -l 64MiB /root/zpool.img") + host.succeed("zpool create test /root/zpool.img") + + with subtest("Check for completed zrepl snapshot"): + # zrepl periodic snapshot job creates a snapshot with this prefix. + host.wait_until_succeeds("zfs list -t snapshot | grep -q zrepl_") + + with subtest("Verify HTTP monitoring server is configured"): + out = host.succeed("curl -f localhost:9811/metrics") + + assert ( + "zrepl_version_daemon" in out + ), "zrepl version metric was not found in Prometheus output" + + assert ( + "zrepl_zfs_snapshot_duration_count{filesystem=\"test\"}" in out + ), "zrepl snapshot counter for test was not found in Prometheus output" + ''; + }) diff --git a/pkgs/tools/backup/zrepl/default.nix b/pkgs/tools/backup/zrepl/default.nix index 999dd6ccb6ee..0bbc7267af80 100644 --- a/pkgs/tools/backup/zrepl/default.nix +++ b/pkgs/tools/backup/zrepl/default.nix @@ -2,6 +2,7 @@ , buildGoModule , fetchFromGitHub , makeWrapper +, nixosTests , openssh }: buildGoModule rec { @@ -32,11 +33,15 @@ buildGoModule rec { --prefix PATH : ${lib.makeBinPath [ openssh ]} ''; + passthru.tests = { + inherit (nixosTests) zrepl; + }; + meta = with lib; { homepage = "https://zrepl.github.io/"; description = "A one-stop, integrated solution for ZFS replication"; platforms = platforms.linux; license = licenses.mit; - maintainers = with maintainers; [ cole-h danderson ]; + maintainers = with maintainers; [ cole-h danderson mdlayher ]; }; }