1import ./make-test-python.nix (
2 { pkgs, ... }:
3
4 let
5 remoteRepository = "/root/restic-backup";
6 remoteFromFileRepository = "/root/restic-backup-from-file";
7 remoteInhibitTestRepository = "/root/restic-backup-inhibit-test";
8 remoteNoInitRepository = "/root/restic-backup-no-init";
9 rcloneRepository = "rclone:local:/root/restic-rclone-backup";
10
11 backupPrepareCommand = ''
12 touch /root/backupPrepareCommand
13 test ! -e /root/backupCleanupCommand
14 '';
15
16 backupCleanupCommand = ''
17 rm /root/backupPrepareCommand
18 touch /root/backupCleanupCommand
19 '';
20
21 testDir = pkgs.stdenvNoCC.mkDerivation {
22 name = "test-files-to-backup";
23 unpackPhase = "true";
24 installPhase = ''
25 mkdir $out
26 echo some_file > $out/some_file
27 echo some_other_file > $out/some_other_file
28 mkdir $out/a_dir
29 echo a_file > $out/a_dir/a_file
30 echo a_file_2 > $out/a_dir/a_file_2
31 '';
32 };
33
34 passwordFile = "${pkgs.writeText "password" "correcthorsebatterystaple"}";
35 paths = [ "/opt" ];
36 exclude = [ "/opt/excluded_file_*" ];
37 pruneOpts = [
38 "--keep-daily 2"
39 "--keep-weekly 1"
40 "--keep-monthly 1"
41 "--keep-yearly 99"
42 ];
43 in
44 {
45 name = "restic";
46
47 meta = with pkgs.lib.maintainers; {
48 maintainers = [
49 bbigras
50 i077
51 ];
52 };
53
54 nodes = {
55 server =
56 { pkgs, ... }:
57 {
58 services.restic.backups = {
59 remotebackup = {
60 inherit
61 passwordFile
62 paths
63 exclude
64 pruneOpts
65 backupPrepareCommand
66 backupCleanupCommand
67 ;
68 repository = remoteRepository;
69 initialize = true;
70 timerConfig = null; # has no effect here, just checking that it doesn't break the service
71 };
72 remote-from-file-backup = {
73 inherit passwordFile exclude pruneOpts;
74 initialize = true;
75 repositoryFile = pkgs.writeText "repositoryFile" remoteFromFileRepository;
76 paths = [
77 "/opt/a_dir/a_file"
78 "/opt/a_dir/a_file_2"
79 ];
80 dynamicFilesFrom = ''
81 find /opt -mindepth 1 -maxdepth 1 ! -name a_dir # all files in /opt except for a_dir
82 '';
83 };
84 inhibit-test = {
85 inherit
86 passwordFile
87 paths
88 exclude
89 pruneOpts
90 ;
91 repository = remoteInhibitTestRepository;
92 initialize = true;
93 inhibitsSleep = true;
94 };
95 remote-noinit-backup = {
96 inherit
97 passwordFile
98 exclude
99 pruneOpts
100 paths
101 ;
102 initialize = false;
103 repository = remoteNoInitRepository;
104 };
105 rclonebackup = {
106 inherit
107 passwordFile
108 paths
109 exclude
110 pruneOpts
111 ;
112 initialize = true;
113 repository = rcloneRepository;
114 rcloneConfig = {
115 type = "local";
116 one_file_system = true;
117 };
118
119 # This gets overridden by rcloneConfig.type
120 rcloneConfigFile = pkgs.writeText "rclone.conf" ''
121 [local]
122 type=ftp
123 '';
124 };
125 remoteprune = {
126 inherit passwordFile;
127 repository = remoteRepository;
128 pruneOpts = [ "--keep-last 1" ];
129 };
130 custompackage = {
131 inherit passwordFile paths;
132 repository = "some-fake-repository";
133 package = pkgs.writeShellScriptBin "restic" ''
134 echo "$@" >> /root/fake-restic.log;
135 '';
136
137 pruneOpts = [ "--keep-last 1" ];
138 checkOpts = [ "--some-check-option" ];
139 };
140 };
141
142 environment.sessionVariables.RCLONE_CONFIG_LOCAL_TYPE = "local";
143 };
144 };
145
146 testScript = ''
147 server.start()
148 server.wait_for_unit("dbus.socket")
149 server.fail(
150 "restic-remotebackup snapshots",
151 'restic-remote-from-file-backup snapshots"',
152 "restic-rclonebackup snapshots",
153 "grep 'backup.* /opt' /root/fake-restic.log",
154 )
155 server.succeed(
156 # set up
157 "cp -rT ${testDir} /opt",
158 "touch /opt/excluded_file_1 /opt/excluded_file_2",
159 "mkdir -p /root/restic-rclone-backup",
160 )
161
162 server.fail(
163 # test that noinit backup in fact does not initialize the repository
164 # and thus fails without a pre-initialized repository
165 "systemctl start restic-backups-remote-noinit-backup.service",
166 )
167
168 server.succeed(
169 # test that remotebackup runs custom commands and produces a snapshot
170 "timedatectl set-time '2016-12-13 13:45'",
171 "systemctl start restic-backups-remotebackup.service",
172 "rm /root/backupCleanupCommand",
173 'restic-remotebackup snapshots --json | ${pkgs.jq}/bin/jq "length | . == 1"',
174
175 # test that restoring that snapshot produces the same directory
176 "mkdir /tmp/restore-1",
177 "restic-remotebackup restore latest -t /tmp/restore-1",
178 "diff -ru ${testDir} /tmp/restore-1/opt",
179
180 # test that remote-from-file-backup produces a snapshot
181 "systemctl start restic-backups-remote-from-file-backup.service",
182 'restic-remote-from-file-backup snapshots --json | ${pkgs.jq}/bin/jq "length | . == 1"',
183 "mkdir /tmp/restore-2",
184 "restic-remote-from-file-backup restore latest -t /tmp/restore-2",
185 "diff -ru ${testDir} /tmp/restore-2/opt",
186
187 # test that remote-noinit-backup produces a snapshot once initialized
188 "restic-remote-noinit-backup init",
189 "systemctl start restic-backups-remote-noinit-backup.service",
190 'restic-remote-noinit-backup snapshots --json | ${pkgs.jq}/bin/jq "length | . == 1"',
191
192 # test that restoring that snapshot produces the same directory
193 "mkdir /tmp/restore-3",
194 "${pkgs.restic}/bin/restic -r ${remoteRepository} -p ${passwordFile} restore latest -t /tmp/restore-3",
195 "diff -ru ${testDir} /tmp/restore-3/opt",
196
197 # test that rclonebackup produces a snapshot
198 "systemctl start restic-backups-rclonebackup.service",
199 'restic-rclonebackup snapshots --json | ${pkgs.jq}/bin/jq "length | . == 1"',
200
201 # test that custompackage runs both `restic backup` and `restic check` with reasonable commandlines
202 "systemctl start restic-backups-custompackage.service",
203 "grep 'backup' /root/fake-restic.log",
204 "grep 'check.* --some-check-option' /root/fake-restic.log",
205
206 # test that we can create four snapshots in remotebackup and rclonebackup
207 "timedatectl set-time '2017-12-13 13:45'",
208 "systemctl start restic-backups-remotebackup.service",
209 "rm /root/backupCleanupCommand",
210 "systemctl start restic-backups-rclonebackup.service",
211
212 "timedatectl set-time '2018-12-13 13:45'",
213 "systemctl start restic-backups-remotebackup.service",
214 "rm /root/backupCleanupCommand",
215 "systemctl start restic-backups-rclonebackup.service",
216
217 "timedatectl set-time '2018-12-14 13:45'",
218 "systemctl start restic-backups-remotebackup.service",
219 "rm /root/backupCleanupCommand",
220 "systemctl start restic-backups-rclonebackup.service",
221
222 "timedatectl set-time '2018-12-15 13:45'",
223 "systemctl start restic-backups-remotebackup.service",
224 "rm /root/backupCleanupCommand",
225 "systemctl start restic-backups-rclonebackup.service",
226
227 "timedatectl set-time '2018-12-16 13:45'",
228 "systemctl start restic-backups-remotebackup.service",
229 "rm /root/backupCleanupCommand",
230 "systemctl start restic-backups-rclonebackup.service",
231
232 'restic-remotebackup snapshots --json | ${pkgs.jq}/bin/jq "length | . == 4"',
233 'restic-rclonebackup snapshots --json | ${pkgs.jq}/bin/jq "length | . == 4"',
234
235 # test that remoteprune brings us back to 1 snapshot in remotebackup
236 "systemctl start restic-backups-remoteprune.service",
237 'restic-remotebackup snapshots --json | ${pkgs.jq}/bin/jq "length | . == 1"',
238
239 )
240
241 # test that the inhibit option is working
242 server.systemctl("start --no-block restic-backups-inhibit-test.service")
243 server.wait_until_succeeds(
244 "systemd-inhibit --no-legend --no-pager | grep -q restic",
245 5
246 )
247 '';
248 }
249)