* [bug#42479] [PATCH] services: Add 'unattended-upgrade-service-type'.
@ 2020-07-22 18:25 Ludovic Courtès
2020-07-22 20:45 ` Oleg Pykhalov
2020-07-25 17:05 ` Marius Bakke
0 siblings, 2 replies; 5+ messages in thread
From: Ludovic Courtès @ 2020-07-22 18:25 UTC (permalink / raw)
To: 42479; +Cc: Ludovic Courtès
* gnu/services/admin.scm (<unattended-upgrade-configuration>): New
record type.
(%unattended-upgrade-log-file): New variable.
(unattended-upgrade-mcron-jobs, unattended-upgrade-log-rotations): New
procedures.
(unattended-upgrade-service-type): New variable.
* doc/guix.texi (Service Reference): Add 'provenance-service-type' anchor.
(Unattended Upgrades): New section.
---
doc/guix.texi | 113 +++++++++++++++++++++++++++++++++
gnu/services/admin.scm | 140 ++++++++++++++++++++++++++++++++++++++++-
2 files changed, 251 insertions(+), 2 deletions(-)
Hi!
So here’s a still somewhat experimental unattended upgrade service,
as a followup to <https://issues.guix.gnu.org/42381>.
Let me know what you think!
Ludo’.
diff --git a/doc/guix.texi b/doc/guix.texi
index 8696a9b554..24cf7bdd6c 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -12908,6 +12908,7 @@ declaration.
* Scheduled Job Execution:: The mcron service.
* Log Rotation:: The rottlog service.
* Networking Services:: Network setup, SSH daemon, etc.
+* Unattended Upgrades:: Automated system upgrades.
* X Window:: Graphical display.
* Printing Services:: Local and remote printer support.
* Desktop Services:: D-Bus and desktop services.
@@ -15278,6 +15279,117 @@ Use this to add additional options and manage shared secrets out-of-band.
@end table
@end deftp
+@node Unattended Upgrades
+@subsection Unattended Upgrades
+
+@cindex unattended upgrades
+@cindex upgrades, unattended
+Guix provides a service to perform @emph{unattended upgrades}:
+periodically, the system automatically reconfigures itself from the
+latest Guix. Guix System has several properties that make unattended
+upgrades safe:
+
+@itemize
+@item
+upgrades are transactional (either the upgrade succeeds or it fails, but
+you cannot end up with an ``in-between'' system state);
+@item
+the upgrade log is kept---you can view it with @command{guix system
+list-generations}---and you can roll back to any previous generation,
+should the upgraded system fail to behave as intended;
+@item
+channel code is authenticated so you know you can only run genuine code
+(@pxref{Channels});
+@item
+@command{guix system reconfigure} prevents downgrades, which makes it
+immune to @dfn{downgrade attacks}.
+@end itemize
+
+To set up unattended upgrades, add an instance of
+@code{unattended-upgrade-service-type} like the one below to the list of
+your operating system services:
+
+@lisp
+(service unattended-upgrade-service-type)
+@end lisp
+
+The defaults above set up weekly upgrades: every Sunday at midnight.
+You do not need to provide the operating system configuration file: it
+uses @file{/run/current-system/configuration.scm}, which ensures it
+always uses your latest configuration---@pxref{provenance-service-type},
+for more information about this file.
+
+There are several things that can be configured, in particular the
+periodicity and services (daemons) to be restarted upon completion.
+When the upgrade is successful, the service takes care of deleting
+system generations older that some threshold, as per @command{guix
+system delete-generations}. See the reference below for details.
+
+To ensure that upgrades are actually happening, you can run
+@command{guix system describe}. To investigate upgrade failures, visit
+the unattended upgrade log file (see below).
+
+@defvr {Scheme Variable} unattended-upgrade-service-type
+This is the service type for unattended upgrades. It sets up an mcron
+job (@pxref{Scheduled Job Execution}) that runs @command{guix system
+reconfigure} from the latest version of the specified channels.
+
+Its value must be a @code{unattended-upgrade-configuration} record (see
+below).
+@end defvr
+
+@deftp {Data Type} unattended-upgrade-configuration
+This data type represents the configuration of the unattended upgrade
+service. The following fields are available:
+
+@table @asis
+@item @code{schedule} (default: @code{"30 01 * * 0"})
+This is the schedule of upgrades, expressed as a gexp containing an
+mcron job schedule (@pxref{Guile Syntax, mcron job specifications,,
+mcron, GNU@tie{}mcron}).
+
+@item @code{channels} (default: @code{#~%default-channels})
+This gexp specifies the channels to use for the upgrade
+(@pxref{Channels}). By default, the tip of the official @code{guix}
+channel is used.
+
+@item @code{services-to-restart} (default: @code{'(mcron)})
+This field specifies the Shepherd services to restart when the upgrade
+completes.
+
+Those services are restarted right away upon completion, as with
+@command{herd restart}, which ensures that the latest version is
+running---remember that by default @command{guix system reconfigure}
+only restarts services that are not currently running, which is
+conservative: it minimizes disruption but leaves outdated services
+running.
+
+By default, the @code{mcron} service is restarted. This ensures that
+the latest version of the unattended upgrade job will be used next time.
+
+@item @code{system-expiration} (default: @code{(* 3 30 24 3600)})
+This is the expiration time in seconds for system generations. System
+generations older that this amount of time are deleted with
+@command{guix system delete-generations} when an upgrade completes.
+
+@quotation Note
+The unattended upgrade service does not run the garbage collector. You
+will probably want to set up your own mcron job to run @command{guix gc}
+periodically.
+@end quotation
+
+@item @code{maximum-duration} (default: @code{3600})
+Maximum duration in seconds for the upgrade; past that time, the upgrade
+aborts.
+
+This is primarily useful to ensure the upgrade does not end up
+rebuilding or re-downloading ``the world''.
+
+@item @code{log-file} (default: @code{"/var/log/unattended-upgrade.log"})
+File where unattended upgrades are logged.
+@end table
+@end deftp
+
@node X Window
@subsection X Window
@@ -29547,6 +29659,7 @@ extend it by passing it lists of packages to add to the system profile.
@end defvr
@cindex provenance tracking, of the operating system
+@anchor{provenance-service-type}
@defvr {Scheme Variable} provenance-service-type
This is the type of the service that records @dfn{provenance meta-data}
in the system itself. It creates several files under
diff --git a/gnu/services/admin.scm b/gnu/services/admin.scm
index 89fa73920d..6ed3de9423 100644
--- a/gnu/services/admin.scm
+++ b/gnu/services/admin.scm
@@ -1,6 +1,6 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2016 Jan Nieuwenhuizen <janneke@gnu.org>
-;;; Copyright © 2016, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2020 Brice Waegeneire <brice@waegenei.re>
;;;
;;; This file is part of GNU Guix.
@@ -20,10 +20,13 @@
(define-module (gnu services admin)
#:use-module (gnu packages admin)
+ #:use-module (gnu packages certs)
+ #:use-module (gnu packages package-management)
#:use-module (gnu services)
#:use-module (gnu services mcron)
#:use-module (gnu services shepherd)
#:use-module (guix gexp)
+ #:use-module (guix modules)
#:use-module (guix packages)
#:use-module (guix records)
#:use-module (srfi srfi-1)
@@ -41,7 +44,17 @@
rottlog-configuration
rottlog-configuration?
rottlog-service
- rottlog-service-type))
+ rottlog-service-type
+
+ unattended-upgrade-service-type
+ unattended-upgrade-configuration
+ unattended-upgrade-configuration?
+ unattended-upgrade-configuration-channels
+ unattended-upgrade-configuration-schedule
+ unattended-upgrade-configuration-services-to-restart
+ unattended-upgrade-configuration-system-expiration
+ unattended-upgrade-configuration-maximum-duration
+ unattended-upgrade-configuration-log-file))
;;; Commentary:
;;;
@@ -177,4 +190,127 @@ Old log files are removed or compressed according to the configuration.")
rotations)))))
(default-value (rottlog-configuration))))
+\f
+;;;
+;;; Unattended upgrade.
+;;;
+
+(define-record-type* <unattended-upgrade-configuration>
+ unattended-upgrade-configuration make-unattended-upgrade-configuration
+ unattended-upgrade-configuration?
+ (schedule unattended-upgrade-configuration-schedule
+ (default "30 01 * * 0"))
+ (channels unattended-upgrade-configuration-channels
+ (default #~%default-channels))
+ (services-to-restart unattended-upgrade-configuration-services-to-restart
+ (default '(mcron)))
+ (system-expiration unattended-upgrade-system-expiration
+ (default (* 3 30 24 3600)))
+ (maximum-duration unattended-upgrade-maximum-duration
+ (default 3600))
+ (log-file unattended-upgrade-configuration-log-file
+ (default %unattended-upgrade-log-file)))
+
+(define %unattended-upgrade-log-file
+ "/var/log/unattended-upgrade.log")
+
+(define (unattended-upgrade-mcron-jobs config)
+ (define channels
+ (scheme-file "channels.scm"
+ (unattended-upgrade-configuration-channels config)))
+
+ (define log
+ (unattended-upgrade-configuration-log-file config))
+
+ (define services
+ (unattended-upgrade-configuration-services-to-restart config))
+
+ (define expiration
+ (unattended-upgrade-system-expiration config))
+
+ (define code
+ (with-imported-modules (source-module-closure '((guix build utils)
+ (gnu services herd)))
+ #~(begin
+ (use-modules (guix build utils)
+ (gnu services herd)
+ (srfi srfi-19)
+ (srfi srfi-34))
+
+ (define log
+ (open-file #$log "a0"))
+
+ (define (timestamp)
+ (date->string (time-utc->date (current-time time-utc))
+ "[~4]"))
+
+ (define (alarm-handler . _)
+ (format #t "~a time is up, aborting upgrade~%"
+ (timestamp))
+ (exit 1))
+
+ (define-syntax-rule (with-logging exp ...)
+ (with-output-to-port log
+ (lambda ()
+ (with-error-to-port log
+ (lambda ()
+ exp ...)))))
+
+ ;; 'guix time-machine' needs X.509 certificates to authenticate the
+ ;; Git host.
+ (setenv "SSL_CERT_DIR"
+ #$(file-append nss-certs "/etc/ssl/certs"))
+
+ ;; Make sure the upgrade doesn't take too long.
+ (sigaction SIGALRM alarm-handler)
+ (alarm #$(unattended-upgrade-maximum-duration config))
+
+ (with-logging
+ (format #t "~a starting upgrade...~%" (timestamp))
+ (guard (c ((invoke-error? c)
+ (report-invoke-error c)))
+ (invoke #$(file-append guix "/bin/guix")
+ "time-machine" "-C" #$channels
+ "--" "system" "reconfigure"
+ "/run/current-system/configuration.scm")
+
+ ;; 'guix system delete-generations' fails when there's no
+ ;; matching generation. Thus, catch 'invoke-error?'.
+ (guard (c ((invoke-error? c)
+ (report-invoke-error c)))
+ (invoke #$(file-append guix "/bin/guix")
+ "system" "delete-generations"
+ #$(string-append (number->string expiration)
+ "s")))
+
+ (format #t "~a restarting services...~%" (timestamp))
+ (for-each restart-service '#$services)
+
+ ;; XXX: If 'mcron' has been restarted, perhaps this isn't
+ ;; reached.
+ (format #t "~a upgrade complete~%" (timestamp)))))))
+
+ (define upgrade
+ (program-file "unattended-upgrade" code))
+
+ (list #~(job #$(unattended-upgrade-configuration-schedule config)
+ #$upgrade)))
+
+(define (unattended-upgrade-log-rotations config)
+ (list (log-rotation
+ (files
+ (list (unattended-upgrade-configuration-log-file config))))))
+
+(define unattended-upgrade-service-type
+ (service-type
+ (name 'unattended-upgrade)
+ (extensions
+ (list (service-extension mcron-service-type
+ unattended-upgrade-mcron-jobs)
+ (service-extension rottlog-service-type
+ unattended-upgrade-log-rotations)))
+ (description
+ "Periodically upgrade the system from the current configuration.")
+ (default-value (unattended-upgrade-configuration))))
+
;;; admin.scm ends here
--
2.27.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [bug#42479] [PATCH] services: Add 'unattended-upgrade-service-type'.
2020-07-22 18:25 [bug#42479] [PATCH] services: Add 'unattended-upgrade-service-type' Ludovic Courtès
@ 2020-07-22 20:45 ` Oleg Pykhalov
2020-07-22 21:46 ` Ludovic Courtès
2020-07-25 17:05 ` Marius Bakke
1 sibling, 1 reply; 5+ messages in thread
From: Oleg Pykhalov @ 2020-07-22 20:45 UTC (permalink / raw)
To: Ludovic Courtès; +Cc: 42479
[-- Attachment #1: Type: text/plain, Size: 341 bytes --]
Hi,
Ludovic Courtès <ludo@gnu.org> writes:
[…]
> +@item @code{log-file} (default: @code{"/var/log/unattended-upgrade.log"})
> +File where unattended upgrades are logged.
> +@end table
> +@end deftp
Maybe better /var/log/guix-unattended-upgrade.log similar to
/var/log/guix-daemon.log and /var/log/guix-publish.log files?
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* [bug#42479] [PATCH] services: Add 'unattended-upgrade-service-type'.
2020-07-22 20:45 ` Oleg Pykhalov
@ 2020-07-22 21:46 ` Ludovic Courtès
0 siblings, 0 replies; 5+ messages in thread
From: Ludovic Courtès @ 2020-07-22 21:46 UTC (permalink / raw)
To: Oleg Pykhalov; +Cc: 42479
Hi Oleg,
Oleg Pykhalov <go.wigust@gmail.com> skribis:
> Ludovic Courtès <ludo@gnu.org> writes:
>
> […]
>
>> +@item @code{log-file} (default: @code{"/var/log/unattended-upgrade.log"})
>> +File where unattended upgrades are logged.
>> +@end table
>> +@end deftp
>
> Maybe better /var/log/guix-unattended-upgrade.log similar to
> /var/log/guix-daemon.log and /var/log/guix-publish.log files?
The service is called “unattended-upgrade” so I thought it was
appropriate (likewise, “guix-daemon” and “guix-publish” are also the
name of the service). WDYT?
(In fact, I think syslog would be better, but that’ll be for another
day…)
Ludo’.
^ permalink raw reply [flat|nested] 5+ messages in thread
* [bug#42479] [PATCH] services: Add 'unattended-upgrade-service-type'.
2020-07-22 18:25 [bug#42479] [PATCH] services: Add 'unattended-upgrade-service-type' Ludovic Courtès
2020-07-22 20:45 ` Oleg Pykhalov
@ 2020-07-25 17:05 ` Marius Bakke
2020-07-27 10:42 ` bug#42479: " Ludovic Courtès
1 sibling, 1 reply; 5+ messages in thread
From: Marius Bakke @ 2020-07-25 17:05 UTC (permalink / raw)
To: Ludovic Courtès, 42479; +Cc: Ludovic Courtès
[-- Attachment #1: Type: text/plain, Size: 539 bytes --]
Ludovic Courtès <ludo@gnu.org> writes:
> * gnu/services/admin.scm (<unattended-upgrade-configuration>): New
> record type.
> (%unattended-upgrade-log-file): New variable.
> (unattended-upgrade-mcron-jobs, unattended-upgrade-log-rotations): New
> procedures.
> (unattended-upgrade-service-type): New variable.
> * doc/guix.texi (Service Reference): Add 'provenance-service-type' anchor.
> (Unattended Upgrades): New section.
Wooohoooo. \o/
Very nice use of the time machine. I have nothing to add other than
LGTM. :-)
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* bug#42479: [PATCH] services: Add 'unattended-upgrade-service-type'.
2020-07-25 17:05 ` Marius Bakke
@ 2020-07-27 10:42 ` Ludovic Courtès
0 siblings, 0 replies; 5+ messages in thread
From: Ludovic Courtès @ 2020-07-27 10:42 UTC (permalink / raw)
To: Marius Bakke; +Cc: 42479-done
Hi,
Marius Bakke <marius@gnu.org> skribis:
> Ludovic Courtès <ludo@gnu.org> writes:
>
>> * gnu/services/admin.scm (<unattended-upgrade-configuration>): New
>> record type.
>> (%unattended-upgrade-log-file): New variable.
>> (unattended-upgrade-mcron-jobs, unattended-upgrade-log-rotations): New
>> procedures.
>> (unattended-upgrade-service-type): New variable.
>> * doc/guix.texi (Service Reference): Add 'provenance-service-type' anchor.
>> (Unattended Upgrades): New section.
>
> Wooohoooo. \o/
>
> Very nice use of the time machine. I have nothing to add other than
> LGTM. :-)
Thanks, pushed as 79501f26ab6d82c0256ff786a5dfb0000b52ccd3!
Ludo’.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2020-07-27 10:43 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-07-22 18:25 [bug#42479] [PATCH] services: Add 'unattended-upgrade-service-type' Ludovic Courtès
2020-07-22 20:45 ` Oleg Pykhalov
2020-07-22 21:46 ` Ludovic Courtès
2020-07-25 17:05 ` Marius Bakke
2020-07-27 10:42 ` bug#42479: " Ludovic Courtès
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/guix.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.