[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#42479: closed ([PATCH] services: Add 'unattended-upgrade-service-typ

From: GNU bug Tracking System
Subject: bug#42479: closed ([PATCH] services: Add 'unattended-upgrade-service-type'.)
Date: Mon, 27 Jul 2020 10:43:02 +0000

Your message dated Mon, 27 Jul 2020 12:42:04 +0200
with message-id <87ime9z1c3.fsf@gnu.org>
and subject line Re: [bug#42479] [PATCH] services: Add 
has caused the debbugs.gnu.org bug report #42479,
regarding [PATCH] services: Add 'unattended-upgrade-service-type'.
to be marked as done.

(If you believe you have received this mail in error, please contact

42479: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=42479
GNU Bug Tracking System
Contact help-debbugs@gnu.org with problems
--- Begin Message --- 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
(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(-)


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!


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:
+upgrades are transactional (either the upgrade succeeds or it fails, but
+you cannot end up with an ``in-between'' system state);
+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;
+channel code is authenticated so you know you can only run genuine code
+@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:
+(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
+@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
+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
+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}
+@end quotation
+@item @code{maximum-duration} (default: @code{3600})
+Maximum duration in seconds for the upgrade; past that time, the upgrade
+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
 @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-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 
    (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

--- End Message ---
--- Begin Message --- Subject: Re: [bug#42479] [PATCH] services: Add 'unattended-upgrade-service-type'. Date: Mon, 27 Jul 2020 12:42:04 +0200 User-agent: Gnus/5.13 (Gnus v5.13) Emacs/26.3 (gnu/linux)

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!


--- End Message ---

reply via email to

[Prev in Thread] Current Thread [Next in Thread]