1{ pkgs, ... }:
2
3let
4 privateKey = ''
5 -----BEGIN OPENSSH PRIVATE KEY-----
6 b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
7 QyNTUxOQAAACBx8UB04Q6Q/fwDFjakHq904PYFzG9pU2TJ9KXpaPMcrwAAAJB+cF5HfnBe
8 RwAAAAtzc2gtZWQyNTUxOQAAACBx8UB04Q6Q/fwDFjakHq904PYFzG9pU2TJ9KXpaPMcrw
9 AAAEBN75NsJZSpt63faCuaD75Unko0JjlSDxMhYHAPJk2/xXHxQHThDpD9/AMWNqQer3Tg
10 9gXMb2lTZMn0pelo8xyvAAAADXJzY2h1ZXR6QGt1cnQ=
11 -----END OPENSSH PRIVATE KEY-----
12 '';
13 publicKey = ''
14 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHHxQHThDpD9/AMWNqQer3Tg9gXMb2lTZMn0pelo8xyv
15 '';
16in
17{
18 name = "btrbk";
19 meta = with pkgs.lib; {
20 maintainers = with maintainers; [ symphorien ];
21 };
22
23 nodes = {
24 archive =
25 { ... }:
26 {
27 environment.systemPackages = with pkgs; [ btrfs-progs ];
28 # note: this makes the privateKey world readable.
29 # don't do it with real ssh keys.
30 environment.etc."btrbk_key".text = privateKey;
31 services.btrbk = {
32 instances = {
33 remote = {
34 onCalendar = "minutely";
35 settings = {
36 ssh_identity = "/etc/btrbk_key";
37 ssh_user = "btrbk";
38 stream_compress = "lz4";
39 volume = {
40 "ssh://main/mnt" = {
41 target = "/mnt";
42 snapshot_dir = "btrbk/remote";
43 subvolume = "to_backup";
44 };
45 };
46 };
47 };
48 };
49 };
50 };
51
52 main =
53 { ... }:
54 {
55 environment.systemPackages = with pkgs; [ btrfs-progs ];
56 services.openssh = {
57 enable = true;
58 settings = {
59 KbdInteractiveAuthentication = false;
60 PasswordAuthentication = false;
61 };
62 };
63 services.btrbk = {
64 extraPackages = [ pkgs.lz4 ];
65 sshAccess = [
66 {
67 key = publicKey;
68 roles = [
69 "source"
70 "send"
71 "info"
72 "delete"
73 ];
74 }
75 ];
76 instances = {
77 local = {
78 onCalendar = "minutely";
79 settings = {
80 volume = {
81 "/mnt" = {
82 snapshot_dir = "btrbk/local";
83 subvolume = "to_backup";
84 };
85 };
86 };
87 };
88 };
89 };
90 };
91 };
92
93 testScript = ''
94 start_all()
95
96 # create btrfs partition at /mnt
97 for machine in (archive, main):
98 machine.succeed("dd if=/dev/zero of=/data_fs bs=120M count=1")
99 machine.succeed("mkfs.btrfs /data_fs")
100 machine.succeed("mkdir /mnt")
101 machine.succeed("mount /data_fs /mnt")
102
103 # what to backup and where
104 main.succeed("btrfs subvolume create /mnt/to_backup")
105 main.succeed("mkdir -p /mnt/btrbk/{local,remote}")
106
107 # check that local snapshots work
108 with subtest("local"):
109 main.succeed("echo foo > /mnt/to_backup/bar")
110 main.wait_until_succeeds("cat /mnt/btrbk/local/*/bar | grep foo")
111 main.succeed("echo bar > /mnt/to_backup/bar")
112 main.succeed("cat /mnt/btrbk/local/*/bar | grep foo")
113
114 # check that btrfs send/receive works and ssh access works
115 with subtest("remote"):
116 archive.wait_until_succeeds("cat /mnt/*/bar | grep bar")
117 main.succeed("echo baz > /mnt/to_backup/bar")
118 archive.succeed("cat /mnt/*/bar | grep bar")
119 '';
120}