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