GNU bug report logs - #42479
[PATCH] services: Add 'unattended-upgrade-service-type'.

Previous Next

Package: guix-patches;

Reported by: Ludovic Courtès <ludo <at> gnu.org>

Date: Wed, 22 Jul 2020 18:26:02 UTC

Severity: normal

Tags: patch

Done: Ludovic Courtès <ludo <at> gnu.org>

Bug is archived. No further changes may be made.

To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 42479 in the body.
You can then email your comments to 42479 AT debbugs.gnu.org in the normal way.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to guix-patches <at> gnu.org:
bug#42479; Package guix-patches. (Wed, 22 Jul 2020 18:26:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to Ludovic Courtès <ludo <at> gnu.org>:
New bug report received and forwarded. Copy sent to guix-patches <at> gnu.org. (Wed, 22 Jul 2020 18:26:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Ludovic Courtès <ludo <at> gnu.org>
To: guix-patches <at> gnu.org
Cc: Ludovic Courtès <ludo <at> gnu.org>
Subject: [PATCH] services: Add 'unattended-upgrade-service-type'.
Date: Wed, 22 Jul 2020 20:25:14 +0200
* 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 <at> 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 <at> gnu.org>
-;;; Copyright © 2016, 2017, 2018, 2019 Ludovic Courtès <ludo <at> gnu.org>
+;;; Copyright © 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo <at> gnu.org>
 ;;; Copyright © 2020 Brice Waegeneire <brice <at> 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))))
 
+
+;;;
+;;; 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





Information forwarded to guix-patches <at> gnu.org:
bug#42479; Package guix-patches. (Wed, 22 Jul 2020 20:46:02 GMT) Full text and rfc822 format available.

Message #8 received at 42479 <at> debbugs.gnu.org (full text, mbox):

From: Oleg Pykhalov <go.wigust <at> gmail.com>
To: Ludovic Courtès <ludo <at> gnu.org>
Cc: 42479 <at> debbugs.gnu.org
Subject: Re: [bug#42479] [PATCH] services: Add
 'unattended-upgrade-service-type'.
Date: Wed, 22 Jul 2020 23:45:35 +0300
[Message part 1 (text/plain, inline)]
Hi,

Ludovic Courtès <ludo <at> 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?
[signature.asc (application/pgp-signature, inline)]

Information forwarded to guix-patches <at> gnu.org:
bug#42479; Package guix-patches. (Wed, 22 Jul 2020 21:47:02 GMT) Full text and rfc822 format available.

Message #11 received at 42479 <at> debbugs.gnu.org (full text, mbox):

From: Ludovic Courtès <ludo <at> gnu.org>
To: Oleg Pykhalov <go.wigust <at> gmail.com>
Cc: 42479 <at> debbugs.gnu.org
Subject: Re: [bug#42479] [PATCH] services: Add
 'unattended-upgrade-service-type'.
Date: Wed, 22 Jul 2020 23:46:29 +0200
Hi Oleg,

Oleg Pykhalov <go.wigust <at> gmail.com> skribis:

> Ludovic Courtès <ludo <at> 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’.




Information forwarded to guix-patches <at> gnu.org:
bug#42479; Package guix-patches. (Sat, 25 Jul 2020 17:06:01 GMT) Full text and rfc822 format available.

Message #14 received at 42479 <at> debbugs.gnu.org (full text, mbox):

From: Marius Bakke <marius <at> gnu.org>
To: Ludovic Courtès <ludo <at> gnu.org>, 42479 <at> debbugs.gnu.org
Cc: Ludovic Courtès <ludo <at> gnu.org>
Subject: Re: [bug#42479] [PATCH] services: Add
 'unattended-upgrade-service-type'.
Date: Sat, 25 Jul 2020 19:05:07 +0200
[Message part 1 (text/plain, inline)]
Ludovic Courtès <ludo <at> 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.  :-)
[signature.asc (application/pgp-signature, inline)]

Reply sent to Ludovic Courtès <ludo <at> gnu.org>:
You have taken responsibility. (Mon, 27 Jul 2020 10:43:02 GMT) Full text and rfc822 format available.

Notification sent to Ludovic Courtès <ludo <at> gnu.org>:
bug acknowledged by developer. (Mon, 27 Jul 2020 10:43:02 GMT) Full text and rfc822 format available.

Message #19 received at 42479-done <at> debbugs.gnu.org (full text, mbox):

From: Ludovic Courtès <ludo <at> gnu.org>
To: Marius Bakke <marius <at> gnu.org>
Cc: 42479-done <at> debbugs.gnu.org
Subject: Re: [bug#42479] [PATCH] services: Add
 'unattended-upgrade-service-type'.
Date: Mon, 27 Jul 2020 12:42:04 +0200
Hi,

Marius Bakke <marius <at> gnu.org> skribis:

> Ludovic Courtès <ludo <at> 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’.




bug archived. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Mon, 24 Aug 2020 11:24:07 GMT) Full text and rfc822 format available.

This bug report was last modified 3 years and 236 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.