[PATCH] services: restic-backup: Implement as a Shepherd timer.

  • Done
  • quality assurance status badge
Details
2 participants
  • Giacomo Leidi
  • Ludovic Courtès
Owner
unassigned
Submitted by
Giacomo Leidi
Severity
normal
G
G
Giacomo Leidi wrote on 23 Dec 2024 11:46
(address . guix-patches@gnu.org)(name . Giacomo Leidi)(address . goodoldpaul@autistici.org)
f52cde358b609d18f43bf62f1dfe63835c1a57b9.1734950765.git.goodoldpaul@autistici.org
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
---
doc/guix.texi | 36 +++++++++----
gnu/services/backup.scm | 114 ++++++++++++++++++++++++++++++++++------
2 files changed, 123 insertions(+), 27 deletions(-)

Toggle diff (257 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 57030102ca..f77b765933 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -41987,19 +41987,16 @@ Miscellaneous Services
"/etc/guix/signing-key.sec"))))))))))
@end lisp
-Each @code{restic-backup-job} translates to an mcron job which sets the
+Each @code{restic-backup-job} translates to a Shepherd timer which sets the
@env{RESTIC_PASSWORD} environment variable by reading the first line of
@code{password-file} and runs @command{restic backup}, creating backups
using rclone of all the files listed in the @code{files} field.
-The @code{restic-backup-service-type} installs as well @code{restic-guix}
-to the system profile, a @code{restic} utility wrapper that allows for easier
-interaction with the Guix configured backup jobs. For example the following
-could be used to instantaneusly trigger a backup for the above shown
-configuration, without waiting for the scheduled job:
+The @code{restic-backup-service-type} provides the ability to instantaneously
+trigger a backup with the @code{trigger} Shepherd action:
@example
-restic-guix backup remote-ftp
+sudo herd trigger remote-ftp-job
@end example
@c %start of fragment
@@ -42030,6 +42027,22 @@ Miscellaneous Services
@item @code{user} (default: @code{"root"}) (type: string)
The user used for running the current job.
+@item @code{group} (default: @code{"root"}) (type: string)
+The group used for running the current job.
+
+@item @code{log-file} (type: maybe-string)
+The file system path to the log file for this job. By default the file will
+have the name of the job and be under @code{/var/log/restic-backup}.
+
+@item @code{max-duration} (type: maybe-number)
+The maximum duration in seconds that a job may last. Past
+@code{max-duration} seconds, the job will forcefully terminated.
+
+@item @code{wait-for-termination?} (default: @code{#f}) (type: boolean)
+Wait until the job has finished before considering executing it again;
+otherwise, perform it strictly on every occurrence of event, at the risk of
+having multiple instances running concurrently.
+
@item @code{repository} (type: string)
The restic repository target of this job.
@@ -42042,9 +42055,12 @@ Miscellaneous Services
for the current job.
@item @code{schedule} (type: gexp-or-string)
-A string or a gexp that will be passed as time specification in the
-mcron job specification (@pxref{Syntax, mcron job specifications,,
-mcron,GNU@tie{}mcron}).
+A string or a gexp representing the frequency of the backup. Gexp must
+evaluate to @code{calendar-event} records or to strings. Strings must contain
+Vixie cron date lines.
+
+@item @code{requirement} (default: @code{'()}) (type: list-of-symbols)
+The list of Shepherd services that this backup job depends upon.
@item @code{files} (default: @code{'()}) (type: list-of-lowerables)
The list of files or directories to be backed up. It must be a list of
diff --git a/gnu/services/backup.scm b/gnu/services/backup.scm
index 555e9fc959..fc8934873b 100644
--- a/gnu/services/backup.scm
+++ b/gnu/services/backup.scm
@@ -18,9 +18,10 @@
(define-module (gnu services backup)
#:use-module (gnu packages backup)
+ #:use-module (gnu packages bash)
#:use-module (gnu services)
#:use-module (gnu services configuration)
- #:use-module (gnu services mcron)
+ #:use-module (gnu services shepherd)
#:use-module (guix build-system copy)
#:use-module (guix gexp)
#:use-module ((guix licenses)
@@ -33,11 +34,16 @@ (define-module (gnu services backup)
restic-backup-job-fields
restic-backup-job-restic
restic-backup-job-user
+ restic-backup-job-group
+ restic-backup-job-log-file
+ restic-backup-job-max-duration
+ restic-backup-job-wait-for-termination?
restic-backup-job-name
restic-backup-job-repository
restic-backup-job-password-file
restic-backup-job-schedule
restic-backup-job-files
+ restic-backup-job-requirement
restic-backup-job-verbose?
restic-backup-job-extra-flags
@@ -64,6 +70,12 @@ (define (lowerable? value)
(define list-of-lowerables?
(list-of lowerable?))
+(define list-of-symbols?
+ (list-of symbol?))
+
+(define-maybe string)
+(define-maybe number)
+
(define-configuration/no-serialization restic-backup-job
(restic
(package restic)
@@ -71,6 +83,22 @@ (define-configuration/no-serialization restic-backup-job
(user
(string "root")
"The user used for running the current job.")
+ (group
+ (string "root")
+ "The group used for running the current job.")
+ (log-file
+ (maybe-string)
+ "The file system path to the log file for this job. By default the file will
+have the name of the job and be under @code{/var/log/restic-backup}.")
+ (max-duration
+ (maybe-number)
+ "The maximum duration in seconds that a job may last. Past
+@code{max-duration} seconds, the job will forcefully terminated.")
+ (wait-for-termination?
+ (boolean #f)
+ "Wait until the job has finished before considering executing it again;
+otherwise, perform it strictly on every occurrence of event, at the risk of
+having multiple instances running concurrently.")
(name
(string)
"A string denoting a name for this job.")
@@ -84,9 +112,12 @@ (define-configuration/no-serialization restic-backup-job
current job.")
(schedule
(gexp-or-string)
- "A string or a gexp that will be passed as time specification in the mcron
-job specification (@pxref{Syntax, mcron job specifications,, mcron,
-GNU@tie{}mcron}).")
+ "A string or a gexp representing the frequency of the backup. Gexp must
+evaluate to @code{calendar-event} records or to strings. Strings must contain
+Vixie cron date lines.")
+ (requirement
+ (list-of-symbols '())
+ "The list of Shepherd services that this backup job depends upon.")
(files
(list-of-lowerables '())
"The list of files or directories to be backed up. It must be a list of
@@ -175,16 +206,56 @@ (define (restic-guix jobs)
(main (command-line)))))
-(define (restic-backup-job->mcron-job config)
- (let ((user
- (restic-backup-job-user config))
- (schedule
- (restic-backup-job-schedule config))
- (name
- (restic-backup-job-name config)))
- #~(job #$schedule
- #$(string-append "restic-guix backup " name)
- #:user #$user)))
+(define (restic-job-log-file job)
+ (let ((name (restic-backup-job-name job))
+ (log-file (restic-backup-job-log-file job)))
+ (if (maybe-value-set? log-file)
+ log-file
+ (string-append "/var/log/restic-backup/" name ".log"))))
+
+(define (restic-backup-job->shepherd-service config)
+ (let ((schedule (restic-backup-job-schedule config))
+ (name (restic-backup-job-name config))
+ (user (restic-backup-job-user config))
+ (group (restic-backup-job-group config))
+ (max-duration (restic-backup-job-max-duration config))
+ (wait-for-termination? (restic-backup-job-wait-for-termination? config))
+ (log-file (restic-job-log-file config))
+ (requirement (restic-backup-job-requirement config)))
+ (shepherd-service (provision `(,(string->symbol
+ (string-append name "-job"))))
+ (requirement
+ `(user-processes file-systems ,@requirement))
+ (documentation
+ "Run @code{restic} backed backups on a regular basis.")
+ (modules '((shepherd service timer)))
+ (start
+ #~(make-timer-constructor
+ (if (string? #$schedule)
+ (cron-string->calendar-event #$schedule)
+ #$schedule)
+ (command
+ (list
+ (string-append #+bash-minimal "/bin/bash")
+ "-l" "-c"
+ (string-append "restic-guix backup " #$name))
+ #:user #$user
+ #:group #$group
+ #:environment-variables
+ (list
+ (string-append
+ "HOME=" (passwd:dir (getpwnam #$user)))))
+ #:log-file #$log-file
+ #:wait-for-termination? #$wait-for-termination?
+ #:max-duration #$(and (maybe-value-set? max-duration)
+ max-duration)))
+ (stop
+ #~(make-timer-destructor))
+ (actions (list (shepherd-action
+ (name 'trigger)
+ (documentation "Manually trigger a backup,
+without waiting for the scheduled time.")
+ (procedure #~trigger-timer)))))))
(define (restic-guix-wrapper-package jobs)
(package
@@ -212,15 +283,24 @@ (define restic-backup-service-profile
(restic-guix-wrapper-package jobs))
'())))
+(define (restic-backup-activation config)
+ #~(for-each
+ (lambda (log-file)
+ (mkdir-p (dirname log-file)))
+ (list #$@(map restic-job-log-file
+ (restic-backup-configuration-jobs config)))))
+
(define restic-backup-service-type
(service-type (name 'restic-backup)
(extensions
(list
+ (service-extension activation-service-type
+ restic-backup-activation)
(service-extension profile-service-type
restic-backup-service-profile)
- (service-extension mcron-service-type
+ (service-extension shepherd-root-service-type
(lambda (config)
- (map restic-backup-job->mcron-job
+ (map restic-backup-job->shepherd-service
(restic-backup-configuration-jobs
config))))))
(compose concatenate)
@@ -232,5 +312,5 @@ (define restic-backup-service-type
jobs)))))
(default-value (restic-backup-configuration))
(description
- "This service configures @code{mcron} jobs for running backups
+ "This service configures @code{Shepherd} timers for running backups
with @code{restic}.")))

base-commit: 2743faebb2893f65fb29a5cfd55c72a66a2b98a9
--
2.46.0
P
block 72803 by 75045
(address . control@debbugs.gnu.org)
581fb166-b3b6-4eab-a349-ff7a75798873@autistici.org
block 72803 by 75045
L
L
Ludovic Courtès wrote on 24 Dec 2024 11:40
Re: [bug#75045] [PATCH] services: restic-backup: Implement as a Shepherd timer.
(name . Giacomo Leidi)(address . goodoldpaul@autistici.org)
87ikr95ppo.fsf@gnu.org
Hi Giacomo,

Giacomo Leidi <goodoldpaul@autistici.org> skribis:

Toggle quote (15 lines)
> 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

Woo, nice!

As mentioned in https://issues.guix.gnu.org/74860, I think we should
postpone a little bit since these new features won’t work for people who
haven’t rebooted into Shepherd 1.0, and they’ll get possibly confusing
messages when reconfiguring.

How we should postpone, I’m not sure. The conservative approach would
be to wait until after the next Guix release, but that doesn’t sound
reasonable… One month after the Shepherd upgrade, which would be
Jan. 9th? It’s common for servers to have much longer uptimes though,
plus there’s end-of-year vacation here.

Toggle quote (5 lines)
> + (log-file
> + (maybe-string)
> + "The file system path to the log file for this job. By default the file will
> +have the name of the job and be under @code{/var/log/restic-backup}.")

Rather @file, with the “.log” suffix too, if I’m not mistaken.

Toggle quote (5 lines)
> + (max-duration
> + (maybe-number)
> + "The maximum duration in seconds that a job may last. Past
> +@code{max-duration} seconds, the job will forcefully terminated.")

s/will/is/

Toggle quote (3 lines)
> + (shepherd-service (provision `(,(string->symbol
> + (string-append name "-job"))))

I would tend to not add the “-job” suffix, but that’s a matter of taste!

Toggle quote (6 lines)
> + (command
> + (list
> + (string-append #+bash-minimal "/bin/bash")
> + "-l" "-c"
> + (string-append "restic-guix backup " #$name))

Why go through bash? Would it be possible to execute ‘restic-guix’
directly?

Toggle quote (5 lines)
> (description
> - "This service configures @code{mcron} jobs for running backups
> + "This service configures @code{Shepherd} timers for running backups
> with @code{restic}.")))

You can drop @code here.
L
L
Ludovic Courtès wrote on 17 Jan 21:28 +0100
(name . Giacomo Leidi)(address . goodoldpaul@autistici.org)
87sephuqvt.fsf@gnu.org
Hello,

Ludovic Courtès <ludo@gnu.org> skribis:

Toggle quote (11 lines)
> As mentioned in https://issues.guix.gnu.org/74860, I think we should
> postpone a little bit since these new features won’t work for people who
> haven’t rebooted into Shepherd 1.0, and they’ll get possibly confusing
> messages when reconfiguring.
>
> How we should postpone, I’m not sure. The conservative approach would
> be to wait until after the next Guix release, but that doesn’t sound
> reasonable… One month after the Shepherd upgrade, which would be
> Jan. 9th? It’s common for servers to have much longer uptimes though,
> plus there’s end-of-year vacation here.

Now that https://issues.guix.gnu.org/74860 is merged, I think we can
gradually start migrating services such as this one. Feel free to send v2!

Ludo’.
P
(name . Ludovic Courtès)(address . ludo@gnu.org)
c76d5c95-2824-442b-a365-9fcd5d15641d@autistici.org
Hi Ludo',

I should have addressed your comments, thank you for your help! I'm
about to send a v2.

On 12/24/24 11:40, Ludovic Courtès wrote:
Toggle quote (7 lines)
>> + (command
>> + (list
>> + (string-append #+bash-minimal "/bin/bash")
>> + "-l" "-c"
>> + (string-append "restic-guix backup " #$name))
> Why go through bash? Would it be possible to execute ‘restic-guix’
> directly?
There may be some better way but we go through bash, instead of
executing restic-guix directly, because the login shell gives us the
correct user environment that some backends require, such as rclone.

I hope this clarifies and I'm definitely open to change this in case we
find a better solution.

cheers,

giacomo
Attachment: file
G
G
Giacomo Leidi wrote on 19 Jan 23:04 +0100
[PATCH v2] services: restic-backup: Implement as a Shepherd timer.
(address . 75045@debbugs.gnu.org)(name . Giacomo Leidi)(address . goodoldpaul@autistici.org)
9b62d9a0cd9f00b074a5871729286925788a0eab.1737324240.git.goodoldpaul@autistici.org
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
---
doc/guix.texi | 39 +++++++++----
gnu/services/backup.scm | 122 +++++++++++++++++++++++++++++++++-------
2 files changed, 131 insertions(+), 30 deletions(-)

Toggle diff (279 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 0015d739bb6..33552065fe3 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -111,7 +111,7 @@
Copyright @copyright{} 2022 John Kehayias@*
Copyright @copyright{} 2022?–?2023 Bruno Victal@*
Copyright @copyright{} 2022 Ivan Vilata-i-Balaguer@*
-Copyright @copyright{} 2023-2024 Giacomo Leidi@*
+Copyright @copyright{} 2023-2025 Giacomo Leidi@*
Copyright @copyright{} 2022 Antero Mejr@*
Copyright @copyright{} 2023 Karl Hallsby@*
Copyright @copyright{} 2023 Nathaniel Nicandro@*
@@ -42709,19 +42709,16 @@ Miscellaneous Services
"/etc/guix/signing-key.sec"))))))))))
@end lisp
-Each @code{restic-backup-job} translates to an mcron job which sets the
+Each @code{restic-backup-job} translates to a Shepherd timer which sets the
@env{RESTIC_PASSWORD} environment variable by reading the first line of
@code{password-file} and runs @command{restic backup}, creating backups
using rclone of all the files listed in the @code{files} field.
-The @code{restic-backup-service-type} installs as well @code{restic-guix}
-to the system profile, a @code{restic} utility wrapper that allows for easier
-interaction with the Guix configured backup jobs. For example the following
-could be used to instantaneusly trigger a backup for the above shown
-configuration, without waiting for the scheduled job:
+The @code{restic-backup-service-type} provides the ability to instantaneously
+trigger a backup with the @code{trigger} Shepherd action:
@example
-restic-guix backup remote-ftp
+sudo herd trigger remote-ftp
@end example
@c %start of fragment
@@ -42752,6 +42749,23 @@ Miscellaneous Services
@item @code{user} (default: @code{"root"}) (type: string)
The user used for running the current job.
+@item @code{group} (default: @code{"root"}) (type: string)
+The group used for running the current job.
+
+@item @code{log-file} (type: maybe-string)
+The file system path to the log file for this job. By default the file will
+have be @file{/var/log/restic-backup/JOB-NAME.log}, where @code{JOB-NAME} is the
+name defined in the @code{name} field.
+
+@item @code{max-duration} (type: maybe-number)
+The maximum duration in seconds that a job may last. Past
+@code{max-duration} seconds, the job is forcefully terminated.
+
+@item @code{wait-for-termination?} (default: @code{#f}) (type: boolean)
+Wait until the job has finished before considering executing it again;
+otherwise, perform it strictly on every occurrence of event, at the risk of
+having multiple instances running concurrently.
+
@item @code{repository} (type: string)
The restic repository target of this job.
@@ -42764,9 +42778,12 @@ Miscellaneous Services
for the current job.
@item @code{schedule} (type: gexp-or-string)
-A string or a gexp that will be passed as time specification in the
-mcron job specification (@pxref{Syntax, mcron job specifications,,
-mcron,GNU@tie{}mcron}).
+A string or a gexp representing the frequency of the backup. Gexp must
+evaluate to @code{calendar-event} records or to strings. Strings must contain
+Vixie cron date lines.
+
+@item @code{requirement} (default: @code{'()}) (type: list-of-symbols)
+The list of Shepherd services that this backup job depends upon.
@item @code{files} (default: @code{'()}) (type: list-of-lowerables)
The list of files or directories to be backed up. It must be a list of
diff --git a/gnu/services/backup.scm b/gnu/services/backup.scm
index 555e9fc9590..3dda6ca370c 100644
--- a/gnu/services/backup.scm
+++ b/gnu/services/backup.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2024 Giacomo Leidi <goodoldpaul@autistici.org>
+;;; Copyright © 2024, 2025 Giacomo Leidi <goodoldpaul@autistici.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -18,9 +18,10 @@
(define-module (gnu services backup)
#:use-module (gnu packages backup)
+ #:use-module (gnu packages bash)
#:use-module (gnu services)
#:use-module (gnu services configuration)
- #:use-module (gnu services mcron)
+ #:use-module (gnu services shepherd)
#:use-module (guix build-system copy)
#:use-module (guix gexp)
#:use-module ((guix licenses)
@@ -33,11 +34,16 @@ (define-module (gnu services backup)
restic-backup-job-fields
restic-backup-job-restic
restic-backup-job-user
+ restic-backup-job-group
+ restic-backup-job-log-file
+ restic-backup-job-max-duration
+ restic-backup-job-wait-for-termination?
restic-backup-job-name
restic-backup-job-repository
restic-backup-job-password-file
restic-backup-job-schedule
restic-backup-job-files
+ restic-backup-job-requirement
restic-backup-job-verbose?
restic-backup-job-extra-flags
@@ -64,6 +70,12 @@ (define (lowerable? value)
(define list-of-lowerables?
(list-of lowerable?))
+(define list-of-symbols?
+ (list-of symbol?))
+
+(define-maybe string)
+(define-maybe number)
+
(define-configuration/no-serialization restic-backup-job
(restic
(package restic)
@@ -71,6 +83,23 @@ (define-configuration/no-serialization restic-backup-job
(user
(string "root")
"The user used for running the current job.")
+ (group
+ (string "root")
+ "The group used for running the current job.")
+ (log-file
+ (maybe-string)
+ "The file system path to the log file for this job. By default the file will
+have be @file{/var/log/restic-backup/JOB-NAME.log}, where @code{JOB-NAME} is the
+name defined in the @code{name} field.")
+ (max-duration
+ (maybe-number)
+ "The maximum duration in seconds that a job may last. Past
+@code{max-duration} seconds, the job is forcefully terminated.")
+ (wait-for-termination?
+ (boolean #f)
+ "Wait until the job has finished before considering executing it again;
+otherwise, perform it strictly on every occurrence of event, at the risk of
+having multiple instances running concurrently.")
(name
(string)
"A string denoting a name for this job.")
@@ -84,9 +113,12 @@ (define-configuration/no-serialization restic-backup-job
current job.")
(schedule
(gexp-or-string)
- "A string or a gexp that will be passed as time specification in the mcron
-job specification (@pxref{Syntax, mcron job specifications,, mcron,
-GNU@tie{}mcron}).")
+ "A string or a gexp representing the frequency of the backup. Gexp must
+evaluate to @code{calendar-event} records or to strings. Strings must contain
+Vixie cron date lines.")
+ (requirement
+ (list-of-symbols '())
+ "The list of Shepherd services that this backup job depends upon.")
(files
(list-of-lowerables '())
"The list of files or directories to be backed up. It must be a list of
@@ -175,16 +207,59 @@ (define (restic-guix jobs)
(main (command-line)))))
-(define (restic-backup-job->mcron-job config)
- (let ((user
- (restic-backup-job-user config))
- (schedule
- (restic-backup-job-schedule config))
- (name
- (restic-backup-job-name config)))
- #~(job #$schedule
- #$(string-append "restic-guix backup " name)
- #:user #$user)))
+(define (restic-job-log-file job)
+ (let ((name (restic-backup-job-name job))
+ (log-file (restic-backup-job-log-file job)))
+ (if (maybe-value-set? log-file)
+ log-file
+ (string-append "/var/log/restic-backup/" name ".log"))))
+
+(define (restic-backup-job->shepherd-service config)
+ (let ((schedule (restic-backup-job-schedule config))
+ (name (restic-backup-job-name config))
+ (user (restic-backup-job-user config))
+ (group (restic-backup-job-group config))
+ (max-duration (restic-backup-job-max-duration config))
+ (wait-for-termination? (restic-backup-job-wait-for-termination? config))
+ (log-file (restic-job-log-file config))
+ (requirement (restic-backup-job-requirement config)))
+ (shepherd-service (provision `(,(string->symbol name)))
+ (requirement
+ `(user-processes file-systems ,@requirement))
+ (documentation
+ "Run @code{restic} backed backups on a regular basis.")
+ (modules '((shepherd service timer)))
+ (start
+ #~(make-timer-constructor
+ (if (string? #$schedule)
+ (cron-string->calendar-event #$schedule)
+ #$schedule)
+ (command
+ (list
+ ;; We go through bash, instead of executing
+ ;; restic-guix directly, because the login shell
+ ;; gives us the correct user environment that some
+ ;; backends require, such as rclone.
+ (string-append #+bash-minimal "/bin/bash")
+ "-l" "-c"
+ (string-append "restic-guix backup " #$name))
+ #:user #$user
+ #:group #$group
+ #:environment-variables
+ (list
+ (string-append
+ "HOME=" (passwd:dir (getpwnam #$user)))))
+ #:log-file #$log-file
+ #:wait-for-termination? #$wait-for-termination?
+ #:max-duration #$(and (maybe-value-set? max-duration)
+ max-duration)))
+ (stop
+ #~(make-timer-destructor))
+ (actions (list (shepherd-action
+ (name 'trigger)
+ (documentation "Manually trigger a backup,
+without waiting for the scheduled time.")
+ (procedure #~trigger-timer)))))))
(define (restic-guix-wrapper-package jobs)
(package
@@ -212,15 +287,24 @@ (define restic-backup-service-profile
(restic-guix-wrapper-package jobs))
'())))
+(define (restic-backup-activation config)
+ #~(for-each
+ (lambda (log-file)
+ (mkdir-p (dirname log-file)))
+ (list #$@(map restic-job-log-file
+ (restic-backup-configuration-jobs config)))))
+
(define restic-backup-service-type
(service-type (name 'restic-backup)
(extensions
(list
+ (service-extension activation-service-type
+ restic-backup-activation)
(service-extension profile-service-type
restic-backup-service-profile)
- (service-extension mcron-service-type
+ (service-extension shepherd-root-service-type
(lambda (config)
- (map restic-backup-job->mcron-job
+ (map restic-backup-job->shepherd-service
(restic-backup-configuration-jobs
config))))))
(compose concatenate)
@@ -232,5 +316,5 @@ (define restic-backup-service-type
jobs)))))
(default-value (restic-backup-configuration))
(description
- "This service configures @code{mcron} jobs for running backups
-with @code{restic}.")))
+ "This service configures @code{Shepherd} timers for running backups
+with restic.")))

base-commit: 5e834c220e81fddb77a26e23cf0cd5055b866844
--
2.47.1
L
L
Ludovic Courtès wrote on 25 Jan 00:01 +0100
(name . Giacomo Leidi)(address . goodoldpaul@autistici.org)
875xm3ddeu.fsf@gnu.org
Giacomo Leidi <goodoldpaul@autistici.org> skribis:

Toggle quote (15 lines)
> 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

Applied with the cosmetic change below, thanks!

I just realized there’s no test for this service, so let’s everything
still works well. Would be nice to add a test.

Toggle quote (8 lines)
> + ;; We go through bash, instead of executing
> + ;; restic-guix directly, because the login shell
> + ;; gives us the correct user environment that some
> + ;; backends require, such as rclone.
> + (string-append #+bash-minimal "/bin/bash")
> + "-l" "-c"
> + (string-append "restic-guix backup " #$name))

Thanks for adding this comment.

Ludo’.
Toggle diff (33 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index d18209f288..9a53bdcd37 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -42755,7 +42755,7 @@ Miscellaneous Services
@item @code{log-file} (type: maybe-string)
The file system path to the log file for this job. By default the file will
-have be @file{/var/log/restic-backup/JOB-NAME.log}, where @code{JOB-NAME} is the
+have be @file{/var/log/restic-backup/@var{job-name}.log}, where @var{job-name} is the
name defined in the @code{name} field.
@item @code{max-duration} (type: maybe-number)
diff --git a/gnu/services/backup.scm b/gnu/services/backup.scm
index 3dda6ca370..6cada58b10 100644
--- a/gnu/services/backup.scm
+++ b/gnu/services/backup.scm
@@ -89,7 +89,7 @@ (define-configuration/no-serialization restic-backup-job
(log-file
(maybe-string)
"The file system path to the log file for this job. By default the file will
-have be @file{/var/log/restic-backup/JOB-NAME.log}, where @code{JOB-NAME} is the
+have be @file{/var/log/restic-backup/@var{job-name}.log}, where @var{job-name} is the
name defined in the @code{name} field.")
(max-duration
(maybe-number)
@@ -316,5 +316,5 @@ (define restic-backup-service-type
jobs)))))
(default-value (restic-backup-configuration))
(description
- "This service configures @code{Shepherd} timers for running backups
+ "This service configures Shepherd timers for running backups
with restic.")))
Closed
L
L
Ludovic Courtès wrote on 25 Jan 00:04 +0100
(name . Giacomo Leidi)(address . goodoldpaul@autistici.org)
871pwrddb0.fsf@gnu.org
And also:
-(define-maybe string)
-(define-maybe number)
+(define-maybe/no-serialization string)
+(define-maybe/no-serialization number)
… to silence a warning about ‘serialize-string’ etc. being unbound.
?
Your comment

Commenting via the web interface is currently disabled.

To comment on this conversation send an email to 75045@debbugs.gnu.org

To respond to this issue using the mumi CLI, first switch to it
mumi current 75045
Then, you may apply the latest patchset in this issue (with sign off)
mumi am -- -s
Or, compose a reply to this issue
mumi compose
Or, send patches to this issue
mumi send-email *.patch