aboutsummaryrefslogtreecommitdiff
path: root/tw/services/restic.scm
diff options
context:
space:
mode:
authorTimo Wilken2023-04-30 00:46:54 +0200
committerTimo Wilken2023-04-30 00:46:54 +0200
commit0f4859d87ad14c2af7f944cada9a5e19e8a6c6ef (patch)
tree4991211cd518777444e1fb0a9dd496ca69ecf808 /tw/services/restic.scm
parente1ff6899f637ff0b4808994d66e982a885bcd150 (diff)
Configure regular restic backups
Diffstat (limited to 'tw/services/restic.scm')
-rw-r--r--tw/services/restic.scm99
1 files changed, 94 insertions, 5 deletions
diff --git a/tw/services/restic.scm b/tw/services/restic.scm
index b0dd18a5..d088e8ba 100644
--- a/tw/services/restic.scm
+++ b/tw/services/restic.scm
@@ -1,15 +1,27 @@
(define-module (tw services restic)
#:use-module (gnu)
+ #:use-module (gnu home services mcron)
#:use-module ((gnu packages admin)
#:select (shadow))
#:use-module (gnu packages backup)
#:use-module (gnu services)
#:use-module (gnu services configuration)
+ #:use-module (gnu services mcron)
#:use-module (gnu services shepherd)
#:use-module (guix gexp)
#:use-module (guix packages)
+ #:use-module (srfi srfi-1)
#:export (restic-server-service-type
- restic-server-configuration))
+ restic-server-configuration
+ home-restic-backup-service-type
+ home-restic-backup-configuration
+ restic-repository))
+
+(define-public %restic-user "restic")
+(define-public %restic-group "restic")
+
+
+;; Restic REST server
(define-maybe/no-serialization integer)
(define-maybe/no-serialization string)
@@ -63,20 +75,20 @@ private restic repos.")
(list #$(file-append (restic-server-configuration-restic-server config)
"/bin/restic-rest-server")
#$@(restic-server-arguments config))
- #:user "restic" #:group "restic"))
+ #:user #$%restic-user #:group #$%restic-group))
(stop #~(make-kill-destructor)))))
(define (restic-server-accounts config)
"Create user accounts and groups for the restic REST server defined in CONFIG."
(list (user-account
- (name "restic")
- (group "restic")
+ (name %restic-user)
+ (group %restic-group)
(comment "Restic server user")
(system? #t)
(home-directory (restic-server-configuration-repository-path config))
(shell (file-append shadow "/sbin/nologin")))
(user-group
- (name "restic")
+ (name %restic-group)
(system? #t))))
(define restic-server-service-type
@@ -87,3 +99,80 @@ private restic repos.")
(service-extension account-service-type restic-server-accounts)))
(description
"Restic REST server, running as a service user instead of root.")))
+
+
+;; Restic cleanup cronjobs
+
+(define-configuration/no-serialization restic-cleanup-repository
+ (repository-path string "The directory path of the restic repository to clean up.")
+ (owner (string %restic-user) "The user that owns the REPOSITORY-PATH.")
+ (group (string %restic-group) "The group that owns the REPOSITORY-PATH."))
+
+(define-configuration/no-serialization restic-cleanup-configuration
+ (restic (package restic) "The restic package to use."))
+
+(define (restic-deletion-service config) #f)
+(define (restic-prune-service config) #f)
+
+(define-public restic-cleanup-service-type
+ (service-type
+ (name 'restic-cleanup)
+ (extensions
+ (list (service-extension mcron-service-type restic-deletion-service)
+ (service-extension mcron-service-type restic-prune-service)))
+ (description
+ "")))
+
+
+;; Restic scheduled backup jobs
+
+(define (nonempty-list-of-strings? thing)
+ (and (pair? thing) (list-of-strings? thing)))
+
+(define-configuration/no-serialization restic-repository
+ (schedule gexp "An mcron schedule, specified as a gexp
+(@pxref{G-Expressions}). String, list or lambda syntax is fine
+(@pxref{Syntax, mcron job specifications,, mcron, GNU@tie{}mcron}).")
+ (paths nonempty-list-of-strings "List of paths to back up. At least one
+must be given. Leading @code{~/} are replaced with @code{$HOME}.")
+ (url-command string "Run this command (inside @code{sh -c}) to obtain the
+directory or URL of the repo to back up to. This allows you to substitute
+passwords in @code{rest:} URLs.")
+ (password-command string "Run this command to obtain the repository password.")
+ (tags (list-of-strings '()) "Optional tags to add to the snapshot.")
+ (restic (package restic) "The restic package to use."))
+
+(define (restic-backup-cronjobs repositories)
+ (define (cronjob repo)
+ #~(job #$(restic-repository-schedule repo)
+ #$(program-file
+ "restic-backup-command"
+ #~(begin
+ (use-modules (ice-9 popen)
+ (ice-9 textual-ports)
+ (srfi srfi-1))
+ (define (replace-home path)
+ (if (string-prefix? "~/" path)
+ (string-replace path (getenv "HOME") 0 1)
+ path))
+ (setenv "RESTIC_PASSWORD_COMMAND"
+ '#$(restic-repository-password-command repo))
+ (let ((pipe (open-pipe '#$(restic-repository-url-command repo) OPEN_READ)))
+ (setenv "RESTIC_REPOSITORY" (string-trim-right (get-string-all pipe) #\newline))
+ (close-pipe pipe))
+ (apply execl #$(file-append (restic-repository-restic repo) "/bin/restic")
+ "restic" "backup"
+ #$@(append-map (lambda (tag) (list "--tag" tag))
+ (restic-repository-tags repo))
+ (map replace-home '#$(restic-repository-paths repo)))))))
+ (map cronjob repositories))
+
+(define home-restic-backup-service-type
+ (service-type
+ (name 'restic-backup)
+ (extensions
+ (list (service-extension home-mcron-service-type restic-backup-cronjobs)))
+ (compose concatenate)
+ (extend append)
+ (default-value '())
+ (description "Run scheduled backup jobs to the specified repos.")))