From 0f4859d87ad14c2af7f944cada9a5e19e8a6c6ef Mon Sep 17 00:00:00 2001 From: Timo Wilken Date: Sun, 30 Apr 2023 00:46:54 +0200 Subject: Configure regular restic backups --- tw/services/restic.scm | 99 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 94 insertions(+), 5 deletions(-) (limited to 'tw/services/restic.scm') 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."))) -- cgit v1.2.3