[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Patches to implement system roll-back and switch-generation
From: |
Ludovic Courtès |
Subject: |
Re: Patches to implement system roll-back and switch-generation |
Date: |
Tue, 04 Oct 2016 12:01:03 +0200 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/25.1 (gnu/linux) |
Hi!
Chris Marusich <address@hidden> skribis:
> Here are some patches which, when applied to
> 1df00601b280db1cdfe0fc8d539ee6c6c726c355, make it possible to switch
> system generations using two new "guix system" subcommands: "roll-back"
> and "switch-generation". These commands currently just rebuild the
> grub.cfg file with a new default entry. As a result, if you want to
> roll back or switch to another system generation, you don't have to
> manually select a previous version every single time you boot, which is
> nice.
Awesome!
> I believe my patch does NOT yet make the regenerated grub.cfg a GC root,
> so it is possible that after rolling back or switching generations,
> invoking GC might clean up some things you'd rather keep around (like
> the grub background image file). Please be careful not to try this
> patch on a machine you care about; please use a VM instead. I've
> verified that it works in a VM.
Indeed. I think you’ll need to extract and reuse the logic in
‘install-grub*’ that installs the GC root.
> Unfortunately, these patches do not apply cleanly to the current master
> branch because of commit 0f65f54ebd76324653fd5506a7dab42ee44d9255. This
> commit has thrown a wrench in my plans. When I try to rebase onto
> master, there are multiple conflicts, and I am not sure yet what the
> best way to resolve them will be. In any case, I think it will be more
> productive to ask for feedback now, rather than to continue on my own
> down uncertain paths.
Sorry about that! Hopefully we can work around the conflicts.
Overall the patches LGTM. You’re going to hate me for that, but could
you please add ChangeLog-style commit logs? Also, could you send the
revised patches using ‘git send-email’?
> From 1741e8a66be3d7e5f647796f434689b0a61e1122 Mon Sep 17 00:00:00 2001
> From: Chris Marusich <address@hidden>
> Date: Tue, 12 Jul 2016 22:58:03 -0700
> Subject: [PATCH 1/9] Improve docstring: switch-to-generation
>
> ---
> guix/profiles.scm | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/guix/profiles.scm b/guix/profiles.scm
> index 4a2ba1c..38f69dd 100644
> --- a/guix/profiles.scm
> +++ b/guix/profiles.scm
> @@ -1011,7 +1011,9 @@ that fails."
>
> (define (switch-to-generation profile number)
> "Atomically switch PROFILE to the generation NUMBER. Return the number of
> -the generation that was current before switching."
> +the generation that was current before switching. Raise a
> +&profile-not-found-error when the profile does not exist. Raise a
> +&missing-generation-error when the generation does not exist."
> (let ((current (generation-number profile))
> (generation (generation-file-name profile number)))
OK.
> From 9f554133be83f06d5a3d0bfc713331e59eb2116c Mon Sep 17 00:00:00 2001
> From: Chris Marusich <address@hidden>
> Date: Tue, 12 Jul 2016 22:53:10 -0700
> Subject: [PATCH 2/9] Refactor: extract procedure:
> relative-generation-spec->number
OK.
> From 42b1f00ce802745fbdc3b9bc5be38ccd47c0af33 Mon Sep 17 00:00:00 2001
> From: Chris Marusich <address@hidden>
> Date: Sat, 16 Jul 2016 15:53:22 -0700
> Subject: [PATCH 3/9] Rename previous-grub-entries to grub-entries
>
> This procedure actually returns an entry for every generation of the profile,
> so its name is confusing if it suggests that it only returns "previous"
> entries.
OK! Maybe ‘profile-grub-entries’ would work too, to suggest that it’s
stateful?
> From a440eb18eaa6c2fe12d91db1c9d62e79823e7ad0 Mon Sep 17 00:00:00 2001
> From: Chris Marusich <address@hidden>
> Date: Mon, 1 Aug 2016 07:51:38 -0700
> Subject: [PATCH 4/9] Fix docstrings: these procedures return derivations
>
> ---
> gnu/system.scm | 4 ++--
> gnu/system/grub.scm | 8 ++++----
> 2 files changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/gnu/system.scm b/gnu/system.scm
> index 7edb018..1d1ed5e 100644
> --- a/gnu/system.scm
> +++ b/gnu/system.scm
> @@ -718,8 +718,8 @@ listed in OS. The C library expects to find it under
> (store-file-system (operating-system-file-systems os)))
>
> (define* (operating-system-grub.cfg os #:optional (old-entries '()))
> - "Return the GRUB configuration file for OS. Use OLD-ENTRIES to populate
> the
> -\"old entries\" menu."
> + "Return a derivation which builds the GRUB configuration file for OS. Use
> +OLD-ENTRIES to populate the \"old entries\" menu."
> (mlet* %store-monad
> ((system (operating-system-derivation os))
> (root-fs -> (operating-system-root-file-system os))
> diff --git a/gnu/system/grub.scm b/gnu/system/grub.scm
> index 4592747..c426d5f 100644
> --- a/gnu/system/grub.scm
> +++ b/gnu/system/grub.scm
> @@ -239,10 +239,10 @@ code."
> #:key
> (system (%current-system))
> (old-entries '()))
> - "Return the GRUB configuration file corresponding to CONFIG, a
> -<grub-configuration> object, and where the store is available at STORE-FS, a
> -<file-system> object. OLD-ENTRIES is taken to be a list of menu entries
> -corresponding to old generations of the system."
> + "Return a derivation which builds the GRUB configuration file corresponding
> +to CONFIG, a <grub-configuration> object, and where the store is available at
> +STORE-FS, a <file-system> object. OLD-ENTRIES is taken to be a list of menu
> +entries corresponding to old generations of the system."
OK, although I often write “Return something” when that really means
“Return a derivation that builds something”.
> From 227ffc6c34c7bef29a39b2745865ac25c28a7e74 Mon Sep 17 00:00:00 2001
> From: Chris Marusich <address@hidden>
> Date: Mon, 1 Aug 2016 08:46:48 -0700
> Subject: [PATCH 5/9] Factor out procedure: device->title
>
> ---
> gnu/build/file-systems.scm | 31 ++++++++++++++++++-------------
> 1 file changed, 18 insertions(+), 13 deletions(-)
>
> diff --git a/gnu/build/file-systems.scm b/gnu/build/file-systems.scm
> index f1fccbd..4a8acd5 100644
> --- a/gnu/build/file-systems.scm
> +++ b/gnu/build/file-systems.scm
> @@ -38,6 +38,7 @@
> find-partition-by-uuid
> find-partition-by-luks-uuid
> canonicalize-device-spec
> + device->title
>
> uuid->string
> string->uuid
> @@ -364,19 +365,6 @@ the following:
> ;; this long.
> 20)
>
> - (define canonical-title
> - ;; The realm of canonicalization.
> - (if (eq? title 'any)
> - (if (string? spec)
> - ;; The "--root=SPEC" kernel command-line option always provides a
> - ;; string, but the string can represent a device, a UUID, or a
> - ;; label. So check for all three.
> - (cond ((string-prefix? "/" spec) 'device)
> - ((string->uuid spec) 'uuid)
> - (else 'label))
> - 'uuid)
> - title))
> -
> (define (resolve find-partition spec fmt)
> (let loop ((count 0))
> (let ((device (find-partition spec)))
> @@ -391,6 +379,10 @@ the following:
> (sleep 1)
> (loop (+ 1 count))))))))
>
> + (define canonical-title (if (eq? title 'any)
Put the “(if” on the next line.
> +(define (device->title device)
> + "Guess the title for the given DEVICE, which must be a device parameter
> from
> +a <file-system> object. As a special case, when the DEVICE is a UUID, it may
> +be specified as a string."
What about calling it ‘inferred-device-title’ instead, since it’s not
just a conversion?
> From 1ade872ffae08ded1b8dae2fca05fee33ac0c69f Mon Sep 17 00:00:00 2001
> From: Chris Marusich <address@hidden>
> Date: Mon, 1 Aug 2016 08:57:08 -0700
> Subject: [PATCH 6/9] gnu/system and gnu/system/grub: use root-fs-device, not
> root-fs
[...]
> -(define (grub-root-search root-fs file)
> - "Return the GRUB 'search' command to look for ROOT-FS, which contains FILE,
> +(define (grub-root-search root-fs-device file)
> + "Return the GRUB 'search' command to look for ROOT-FS-DEVICE, which
> contains FILE,
> a gexp. The result is a gexp that can be inserted in the grub.cfg-generation
> code."
> - (case (file-system-title root-fs)
> - ;; Preferably refer to ROOT-FS by its UUID or label. This is more
> - ;; efficient and less ambiguous, see <>.
> + (case (device->title root-fs-device)
> + ;; Preferably refer to ROOT-FS-DEVICE by its UUID or label. This is more
> + ;; efficient and less ambiguous.
I’m not convinced by this patch. What’s the rationale? To better deal
with cases where the title is 'any?
> From 55cf900abf6dba10ed640d24433cc1ca23e4acf2 Mon Sep 17 00:00:00 2001
> From: Chris Marusich <address@hidden>
> Date: Tue, 2 Aug 2016 21:28:21 -0700
> Subject: [PATCH 7/9] gnu/build/install: Factor out procedure:
> install-grub-config
OK.
> From 059e79ab26f5e8ee60b60f5df01907300346c8e2 Mon Sep 17 00:00:00 2001
> From: Chris Marusich <address@hidden>
> Date: Thu, 28 Jul 2016 02:31:38 -0700
> Subject: [PATCH 8/9] grub-entries: take a list of numbers on input
OK.
> From b5816897c6db7984f678963dabe8ae58c6947677 Mon Sep 17 00:00:00 2001
> From: Chris Marusich <address@hidden>
> Date: Wed, 3 Aug 2016 00:41:01 -0700
> Subject: [PATCH 9/9] Implement switch-generation and roll-back
>
> ---
> guix/scripts/system.scm | 87
> ++++++++++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 83 insertions(+), 4 deletions(-)
>
> diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm
> index f450c9a..5c72808 100644
> --- a/guix/scripts/system.scm
> +++ b/guix/scripts/system.scm
> @@ -408,6 +408,57 @@ NUMBERS, which is a list of generation numbers."
>
>
> ;;;
> +;;; Roll-back.
> +;;;
> +(define (roll-back-system store)
> + "Roll back the system profile to its previous generation."
> + (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."
> + (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."
> + (unless-file-not-found
> + (let*
> + ((generation (generation-file-name %system-profile number))
No newline after ‘let*’.
> + (file (string-append generation "/parameters"))
> + (params (call-with-input-file file read-boot-parameters))
> + ;; We assume that the root file system contains the store. If this
> + ;; assumption is ever false, then problems might occur.
> + (root-device (boot-parameters-root-device params))
> + ;; Generate a new grub configuration which uses default values for
> + ;; just about everything. If the specified system generation was
> + ;; built from an operating system configuration file that contained
> + ;; non-default values in its grub-configuration, then the grub
> + ;; configuration we generate here will be different. However, even
> + ;; if that is the case, this default configuration will be good
> + ;; enough to enable the user to boot into the specified generation.
> + (grub-config (grub-configuration (device root-device)))
> + ;; Make the specified system generation the default entry.
> + (entries (grub-entries %system-profile (list number)))
> + (old-entries (grub-entries))
Should we remove NUMBER from OLD-ENTRIES?
> + (grub.cfg-derivation (run-with-store store
> + (grub-configuration-file grub-config
> + root-device
> + entries
> + #:old-entries old-entries))))
> + (build-derivations store (list grub.cfg-derivation))
Add call to ‘show-what-to-build’ before. I’d remove “-derivation” from
the identifier, that’s not very helpful IMO. :-)
> + (install-grub-config (derivation->output-path grub.cfg-derivation)
> "/"))))
And yeah, GRUB.CFG must be registered as a GC root before we can safely
apply this patch.
The rest LGTM. We’ll also need a few lines describing these actions in
guix.texi.
Thanks a lot for this very useful contribution!
Ludo’.
- Re: Patches to implement system roll-back and switch-generation,
Ludovic Courtès <=