system: Add 'guix system' actions: switch-generation and roll-back.
* guix/scripts/system.scm (roll-back-system, switch-to-system-generation): new actions. (reinstall-grub): New procedure, used by switch-to-system-generation. (show-help, process-command, guix-system): Honor the new actions. * doc/guix.texi (Invoking guix system) <switch-generation, roll-back>: Add the new actions. <reconfigure>: In the footnote, mention that the new actions also only work on GuixSD. Signed-off-by: Ludovic Courtès <ludo@gnu.org>master
parent
1e17a2d5f2
commit
8074b33077
|
@ -11155,8 +11155,9 @@ supported:
|
|||
@table @code
|
||||
@item reconfigure
|
||||
Build the operating system described in @var{file}, activate it, and
|
||||
switch to it@footnote{This action is usable only on systems already
|
||||
running GuixSD.}.
|
||||
switch to it@footnote{This action (and the related actions
|
||||
@code{switch-generation} and @code{roll-back}) are usable only on
|
||||
systems already running GuixSD.}.
|
||||
|
||||
This effects all the configuration specified in @var{file}: user
|
||||
accounts, system services, global package list, setuid programs, etc.
|
||||
|
@ -11178,6 +11179,52 @@ guix pull}). Failing to do that you would see an older version of Guix
|
|||
once @command{reconfigure} has completed.
|
||||
@end quotation
|
||||
|
||||
@item switch-generation
|
||||
Switch to an existing system generation. This action atomically
|
||||
switches the system profile to the specified system generation. It also
|
||||
rearranges the system's existing GRUB menu entries. It makes the menu
|
||||
entry for the specified system generation the default, and it moves the
|
||||
entries for the other generations to a submenu. The next time the
|
||||
system boots, it will use the specified system generation.
|
||||
|
||||
The target generation can be specified explicitly by its generation
|
||||
number. For example, the following invocation would switch to system
|
||||
generation 7:
|
||||
|
||||
@example
|
||||
guix system switch-generation 7
|
||||
@end example
|
||||
|
||||
The target generation can also be specified relative to the current
|
||||
generation with the form @code{+N} or @code{-N}, where @code{+3} means
|
||||
``3 generations ahead of the current generation,'' and @code{-1} means
|
||||
``1 generation prior to the current generation.'' When specifying a
|
||||
negative value such as @code{-1}, you must precede it with @code{--} to
|
||||
prevent it from being parsed as an option. For example:
|
||||
|
||||
@example
|
||||
guix system switch-generation -- -1
|
||||
@end example
|
||||
|
||||
Currently, the effect of invoking this action is @emph{only} to switch
|
||||
the system profile to an existing generation and rearrange the GRUB menu
|
||||
entries. To actually start using the target system generation, you must
|
||||
reboot after running this action. In the future, it will be updated to
|
||||
do the same things as @command{reconfigure}, like activating and
|
||||
deactivating services.
|
||||
|
||||
This action will fail if the specified generation does not exist.
|
||||
|
||||
@item roll-back
|
||||
Switch to the preceding system generation. The next time the system
|
||||
boots, it will use the preceding system generation. This is the inverse
|
||||
of @command{reconfigure}, and it is exactly the same as invoking
|
||||
@command{switch-generation} with an argument of @code{-1}.
|
||||
|
||||
Currently, as with @command{switch-generation}, you must reboot after
|
||||
running this action to actually start using the preceding system
|
||||
generation.
|
||||
|
||||
@item build
|
||||
Build the derivation of the operating system, which includes all the
|
||||
configuration files and programs needed to boot and run the system.
|
||||
|
|
|
@ -405,6 +405,65 @@ NUMBERS, which is a list of generation numbers."
|
|||
systems)))
|
||||
(filter-map system->grub-entry systems numbers times)))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Roll-back.
|
||||
;;;
|
||||
(define (roll-back-system store)
|
||||
"Roll back the system profile to its previous generation. STORE is an open
|
||||
connection to the store."
|
||||
(switch-to-system-generation store "-1"))
|
||||
|
||||
;;;
|
||||
;;; Switch generations.
|
||||
;;;
|
||||
(define (switch-to-system-generation store spec)
|
||||
"Switch the system profile to the generation specified by SPEC, and
|
||||
re-install grub with a grub configuration file that uses the specified system
|
||||
generation as its default entry. STORE is an open connection to the store."
|
||||
(let ((number (relative-generation-spec->number %system-profile spec)))
|
||||
(if number
|
||||
(begin
|
||||
(reinstall-grub store number)
|
||||
(switch-to-generation* %system-profile number))
|
||||
(leave (_ "cannot switch to system generation '~a'~%") spec))))
|
||||
|
||||
(define (reinstall-grub store number)
|
||||
"Re-install grub for existing system profile generation NUMBER. STORE is an
|
||||
open connection to the store."
|
||||
(let* ((generation (generation-file-name %system-profile number))
|
||||
(file (string-append generation "/parameters"))
|
||||
(params (unless-file-not-found
|
||||
(call-with-input-file file read-boot-parameters)))
|
||||
(root-device (boot-parameters-root-device params))
|
||||
;; We don't currently keep track of past menu entries' details. The
|
||||
;; default values will allow the system to boot, even if they differ
|
||||
;; from the actual past values for this generation's entry.
|
||||
(grub-config (grub-configuration (device root-device)))
|
||||
;; Make the specified system generation the default entry.
|
||||
(entries (profile-grub-entries %system-profile (list number)))
|
||||
(old-generations (delv number (generation-numbers %system-profile)))
|
||||
(old-entries (profile-grub-entries %system-profile old-generations))
|
||||
(grub.cfg (run-with-store store
|
||||
(grub-configuration-file grub-config
|
||||
entries
|
||||
#:old-entries old-entries))))
|
||||
(show-what-to-build store (list grub.cfg))
|
||||
(build-derivations store (list grub.cfg))
|
||||
;; This is basically the same as install-grub*, but for now we avoid
|
||||
;; re-installing the GRUB boot loader itself onto a device, mainly because
|
||||
;; we don't in general have access to the same version of the GRUB package
|
||||
;; which was used when installing this other system generation.
|
||||
(let* ((grub.cfg-path (derivation->output-path grub.cfg))
|
||||
(gc-root (string-append %gc-roots-directory "/grub.cfg"))
|
||||
(temp-gc-root (string-append gc-root ".new")))
|
||||
(switch-symlinks temp-gc-root grub.cfg-path)
|
||||
(unless (false-if-exception (install-grub-config grub.cfg-path "/"))
|
||||
(delete-file temp-gc-root)
|
||||
(leave (_ "failed to re-install GRUB configuration file: '~a'~%")
|
||||
grub.cfg-path))
|
||||
(rename-file temp-gc-root gc-root))))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Graphs.
|
||||
|
@ -641,13 +700,18 @@ building anything."
|
|||
;;;
|
||||
|
||||
(define (show-help)
|
||||
(display (_ "Usage: guix system [OPTION] ACTION [FILE]
|
||||
Build the operating system declared in FILE according to ACTION.\n"))
|
||||
(display (_ "Usage: guix system [OPTION ...] ACTION [ARG ...] [FILE]
|
||||
Build the operating system declared in FILE according to ACTION.
|
||||
Some ACTIONS support additional ARGS.\n"))
|
||||
(newline)
|
||||
(display (_ "The valid values for ACTION are:\n"))
|
||||
(newline)
|
||||
(display (_ "\
|
||||
reconfigure switch to a new operating system configuration\n"))
|
||||
(display (_ "\
|
||||
roll-back switch to the previous operating system configuration\n"))
|
||||
(display (_ "\
|
||||
switch-generation switch to an existing operating system configuration\n"))
|
||||
(display (_ "\
|
||||
list-generations list the system generations\n"))
|
||||
(display (_ "\
|
||||
|
@ -809,15 +873,33 @@ resulting from command-line parsing."
|
|||
"Process COMMAND, one of the 'guix system' sub-commands. ARGS is its
|
||||
argument list and OPTS is the option alist."
|
||||
(case command
|
||||
;; The following commands do not need to use the store, and they do not need
|
||||
;; an operating system configuration file.
|
||||
((list-generations)
|
||||
;; List generations. No need to connect to the daemon, etc.
|
||||
(let ((pattern (match args
|
||||
(() "")
|
||||
((pattern) pattern)
|
||||
(x (leave (_ "wrong number of arguments~%"))))))
|
||||
(list-generations pattern)))
|
||||
(else
|
||||
(process-action command args opts))))
|
||||
;; The following commands need to use the store, but they do not need an
|
||||
;; operating system configuration file.
|
||||
((switch-generation)
|
||||
(let ((pattern (match args
|
||||
((pattern) pattern)
|
||||
(x (leave (_ "wrong number of arguments~%"))))))
|
||||
(with-store store
|
||||
(set-build-options-from-command-line store opts)
|
||||
(switch-to-system-generation store pattern))))
|
||||
((roll-back)
|
||||
(let ((pattern (match args
|
||||
(() "")
|
||||
(x (leave (_ "wrong number of arguments~%"))))))
|
||||
(with-store store
|
||||
(set-build-options-from-command-line store opts)
|
||||
(roll-back-system store))))
|
||||
;; The following commands need to use the store, and they also
|
||||
;; need an operating system configuration file.
|
||||
(else (process-action command args opts))))
|
||||
|
||||
(define (guix-system . args)
|
||||
(define (parse-sub-command arg result)
|
||||
|
@ -827,7 +909,8 @@ argument list and OPTS is the option alist."
|
|||
(let ((action (string->symbol arg)))
|
||||
(case action
|
||||
((build container vm vm-image disk-image reconfigure init
|
||||
extension-graph shepherd-graph list-generations)
|
||||
extension-graph shepherd-graph list-generations roll-back
|
||||
switch-generation)
|
||||
(alist-cons 'action action result))
|
||||
(else (leave (_ "~a: unknown action~%") action))))))
|
||||
|
||||
|
|
Reference in New Issue