summaryrefslogtreecommitdiff
path: root/gnu
diff options
context:
space:
mode:
authorGiacomo Leidi <goodoldpaul@autistici.org>2025-01-19 23:04:00 +0100
committerLudovic Courtès <ludo@gnu.org>2025-01-25 00:04:27 +0100
commit35c6ae6e58f1cfd397602d12c4f4e70d37f0eb90 (patch)
treefd6e79d4783af33baf9e78c6ae9b3a36df8961ec /gnu
parent44d12f9663ca363134636588279ef70decd1d551 (diff)
services: restic-backup: Implement as a Shepherd timer.
This patch implements restic backup with Shepherd services. It is supposed not to break any existing setup. * gnu/services/backup.scm (restic-backup-job): Add Shepherd configuration options; (restic-backup-job->mcron-job): Replace with...; (restic-job-log-file): New procedure; (restic-backup-job->shepherd-service): New procedure; (restic-backup-activation): New procedure; (restic-backup-service-type): Replace mcron with Shepherd extension and add activation extension hook. * doc/guix.texi: Document it. Change-Id: I66de3b6a1cb6177f9e4ee0c2acf3013ecbcdd338 Signed-off-by: Ludovic Courtès <ludo@gnu.org>
Diffstat (limited to 'gnu')
-rw-r--r--gnu/services/backup.scm122
1 files changed, 103 insertions, 19 deletions
diff --git a/gnu/services/backup.scm b/gnu/services/backup.scm
index 555e9fc9590..99a79ff5fbe 100644
--- a/gnu/services/backup.scm
+++ b/gnu/services/backup.scm
@@ -1,5 +1,5 @@
1;;; GNU Guix --- Functional package management for GNU 1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2024 Giacomo Leidi <goodoldpaul@autistici.org> 2;;; Copyright © 2024, 2025 Giacomo Leidi <goodoldpaul@autistici.org>
3;;; 3;;;
4;;; This file is part of GNU Guix. 4;;; This file is part of GNU Guix.
5;;; 5;;;
@@ -18,9 +18,10 @@
18 18
19(define-module (gnu services backup) 19(define-module (gnu services backup)
20 #:use-module (gnu packages backup) 20 #:use-module (gnu packages backup)
21 #:use-module (gnu packages bash)
21 #:use-module (gnu services) 22 #:use-module (gnu services)
22 #:use-module (gnu services configuration) 23 #:use-module (gnu services configuration)
23 #:use-module (gnu services mcron) 24 #:use-module (gnu services shepherd)
24 #:use-module (guix build-system copy) 25 #:use-module (guix build-system copy)
25 #:use-module (guix gexp) 26 #:use-module (guix gexp)
26 #:use-module ((guix licenses) 27 #:use-module ((guix licenses)
@@ -33,11 +34,16 @@
33 restic-backup-job-fields 34 restic-backup-job-fields
34 restic-backup-job-restic 35 restic-backup-job-restic
35 restic-backup-job-user 36 restic-backup-job-user
37 restic-backup-job-group
38 restic-backup-job-log-file
39 restic-backup-job-max-duration
40 restic-backup-job-wait-for-termination?
36 restic-backup-job-name 41 restic-backup-job-name
37 restic-backup-job-repository 42 restic-backup-job-repository
38 restic-backup-job-password-file 43 restic-backup-job-password-file
39 restic-backup-job-schedule 44 restic-backup-job-schedule
40 restic-backup-job-files 45 restic-backup-job-files
46 restic-backup-job-requirement
41 restic-backup-job-verbose? 47 restic-backup-job-verbose?
42 restic-backup-job-extra-flags 48 restic-backup-job-extra-flags
43 49
@@ -64,6 +70,12 @@
64(define list-of-lowerables? 70(define list-of-lowerables?
65 (list-of lowerable?)) 71 (list-of lowerable?))
66 72
73(define list-of-symbols?
74 (list-of symbol?))
75
76(define-maybe/no-serialization string)
77(define-maybe/no-serialization number)
78
67(define-configuration/no-serialization restic-backup-job 79(define-configuration/no-serialization restic-backup-job
68 (restic 80 (restic
69 (package restic) 81 (package restic)
@@ -71,6 +83,23 @@
71 (user 83 (user
72 (string "root") 84 (string "root")
73 "The user used for running the current job.") 85 "The user used for running the current job.")
86 (group
87 (string "root")
88 "The group used for running the current job.")
89 (log-file
90 (maybe-string)
91 "The file system path to the log file for this job. By default the file will
92have be @file{/var/log/restic-backup/@var{job-name}.log}, where @var{job-name} is the
93name defined in the @code{name} field.")
94 (max-duration
95 (maybe-number)
96 "The maximum duration in seconds that a job may last. Past
97@code{max-duration} seconds, the job is forcefully terminated.")
98 (wait-for-termination?
99 (boolean #f)
100 "Wait until the job has finished before considering executing it again;
101otherwise, perform it strictly on every occurrence of event, at the risk of
102having multiple instances running concurrently.")
74 (name 103 (name
75 (string) 104 (string)
76 "A string denoting a name for this job.") 105 "A string denoting a name for this job.")
@@ -84,9 +113,12 @@ will be used to set the @code{RESTIC_PASSWORD} environment variable for the
84current job.") 113current job.")
85 (schedule 114 (schedule
86 (gexp-or-string) 115 (gexp-or-string)
87 "A string or a gexp that will be passed as time specification in the mcron 116 "A string or a gexp representing the frequency of the backup. Gexp must
88job specification (@pxref{Syntax, mcron job specifications,, mcron, 117evaluate to @code{calendar-event} records or to strings. Strings must contain
89GNU@tie{}mcron}).") 118Vixie cron date lines.")
119 (requirement
120 (list-of-symbols '())
121 "The list of Shepherd services that this backup job depends upon.")
90 (files 122 (files
91 (list-of-lowerables '()) 123 (list-of-lowerables '())
92 "The list of files or directories to be backed up. It must be a list of 124 "The list of files or directories to be backed up. It must be a list of
@@ -175,16 +207,59 @@ command-line arguments to the current job @command{restic backup} invokation."))
175 207
176 (main (command-line))))) 208 (main (command-line)))))
177 209
178(define (restic-backup-job->mcron-job config) 210(define (restic-job-log-file job)
179 (let ((user 211 (let ((name (restic-backup-job-name job))
180 (restic-backup-job-user config)) 212 (log-file (restic-backup-job-log-file job)))
181 (schedule 213 (if (maybe-value-set? log-file)
182 (restic-backup-job-schedule config)) 214 log-file
183 (name 215 (string-append "/var/log/restic-backup/" name ".log"))))
184 (restic-backup-job-name config))) 216
185 #~(job #$schedule 217(define (restic-backup-job->shepherd-service config)
186 #$(string-append "restic-guix backup " name) 218 (let ((schedule (restic-backup-job-schedule config))
187 #:user #$user))) 219 (name (restic-backup-job-name config))
220 (user (restic-backup-job-user config))
221 (group (restic-backup-job-group config))
222 (max-duration (restic-backup-job-max-duration config))
223 (wait-for-termination? (restic-backup-job-wait-for-termination? config))
224 (log-file (restic-job-log-file config))
225 (requirement (restic-backup-job-requirement config)))
226 (shepherd-service (provision `(,(string->symbol name)))
227 (requirement
228 `(user-processes file-systems ,@requirement))
229 (documentation
230 "Run @code{restic} backed backups on a regular basis.")
231 (modules '((shepherd service timer)))
232 (start
233 #~(make-timer-constructor
234 (if (string? #$schedule)
235 (cron-string->calendar-event #$schedule)
236 #$schedule)
237 (command
238 (list
239 ;; We go through bash, instead of executing
240 ;; restic-guix directly, because the login shell
241 ;; gives us the correct user environment that some
242 ;; backends require, such as rclone.
243 (string-append #+bash-minimal "/bin/bash")
244 "-l" "-c"
245 (string-append "restic-guix backup " #$name))
246 #:user #$user
247 #:group #$group
248 #:environment-variables
249 (list
250 (string-append
251 "HOME=" (passwd:dir (getpwnam #$user)))))
252 #:log-file #$log-file
253 #:wait-for-termination? #$wait-for-termination?
254 #:max-duration #$(and (maybe-value-set? max-duration)
255 max-duration)))
256 (stop
257 #~(make-timer-destructor))
258 (actions (list (shepherd-action
259 (name 'trigger)
260 (documentation "Manually trigger a backup,
261without waiting for the scheduled time.")
262 (procedure #~trigger-timer)))))))
188 263
189(define (restic-guix-wrapper-package jobs) 264(define (restic-guix-wrapper-package jobs)
190 (package 265 (package
@@ -212,15 +287,24 @@ without waiting for the scheduled job to run.")
212 (restic-guix-wrapper-package jobs)) 287 (restic-guix-wrapper-package jobs))
213 '()))) 288 '())))
214 289
290(define (restic-backup-activation config)
291 #~(for-each
292 (lambda (log-file)
293 (mkdir-p (dirname log-file)))
294 (list #$@(map restic-job-log-file
295 (restic-backup-configuration-jobs config)))))
296
215(define restic-backup-service-type 297(define restic-backup-service-type
216 (service-type (name 'restic-backup) 298 (service-type (name 'restic-backup)
217 (extensions 299 (extensions
218 (list 300 (list
301 (service-extension activation-service-type
302 restic-backup-activation)
219 (service-extension profile-service-type 303 (service-extension profile-service-type
220 restic-backup-service-profile) 304 restic-backup-service-profile)
221 (service-extension mcron-service-type 305 (service-extension shepherd-root-service-type
222 (lambda (config) 306 (lambda (config)
223 (map restic-backup-job->mcron-job 307 (map restic-backup-job->shepherd-service
224 (restic-backup-configuration-jobs 308 (restic-backup-configuration-jobs
225 config)))))) 309 config))))))
226 (compose concatenate) 310 (compose concatenate)
@@ -232,5 +316,5 @@ without waiting for the scheduled job to run.")
232 jobs))))) 316 jobs)))))
233 (default-value (restic-backup-configuration)) 317 (default-value (restic-backup-configuration))
234 (description 318 (description
235 "This service configures @code{mcron} jobs for running backups 319 "This service configures Shepherd timers for running backups
236with @code{restic}."))) 320with restic.")))