From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:470:142:3::10]:37822) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hmFCF-00087k-O1 for guix-patches@gnu.org; Sat, 13 Jul 2019 06:24:05 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hmFCE-0006c4-4Y for guix-patches@gnu.org; Sat, 13 Jul 2019 06:24:03 -0400 Received: from debbugs.gnu.org ([209.51.188.43]:60906) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1hmFCE-0006au-0B for guix-patches@gnu.org; Sat, 13 Jul 2019 06:24:02 -0400 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1hmFCD-00023g-Pk for guix-patches@gnu.org; Sat, 13 Jul 2019 06:24:01 -0400 Subject: [bug#36555] [PATCH 1/2] guix system: Add 'reconfigure' module. Resent-Message-ID: From: Ludovic =?UTF-8?Q?Court=C3=A8s?= References: <87imsci9sj.fsf@sdf.lonestar.org> <87ef30i9fl.fsf@sdf.lonestar.org> Date: Sat, 13 Jul 2019 12:23:20 +0200 In-Reply-To: <87ef30i9fl.fsf@sdf.lonestar.org> (Jakob L. Kreuze's message of "Mon, 08 Jul 2019 15:59:58 -0400") Message-ID: <87y3129qsn.fsf@gnu.org> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+kyle=kyleam.com@gnu.org Sender: "Guix-patches" To: "Jakob L. Kreuze" Cc: 36555@debbugs.gnu.org Hello! zerodaysfordays@sdf.lonestar.org (Jakob L. Kreuze) skribis: > * guix/scripts/system/reconfigure.scm: New file. > * Makefile.am (MODULES): Add it. > * guix/scripts/system.scm (bootloader-installer-script): Export variable. > * gnu/machine/ssh.scm (switch-to-system, upgrade-shepherd-services) > (install-bootloader): Delete variable. > * gnu/machine/ssh.scm (deploy-managed-host): Rewrite procedure. [...] > + (define (run-switch-to-system machine) > + "Monadic procedure serializing the items in MACHINE necessary to bui= ld a > +G-Expression with 'switch-to-system'." > + (mlet %store-monad ((script (switch-system-program (machine-system m= achine)))) > + (machine-remote-eval machine #~(primitive-load #$script)))) > + > + (define (run-upgrade-shepherd-services machine) > + "Monadic procedure serializing the items in MACHINE necessary to bui= ld a > +G-Expression with 'upgrade-shepherd-services'." > + (mlet* %store-monad ((target-services target-services) > + (script (upgrade-services-program target-servic= es))) > + (machine-remote-eval machine #~(primitive-load #$script)))) These would look nicer if =E2=80=98switch-system-program=E2=80=99 and =E2=80=98upgrade-services-program=E2=80=99 returns a because= you could just write: (machine-remote-eval #~(primitive-load #$(switch-system-program =E2=80=A6= )) machine) (I realize the order of arguments is reversed; to stick to what =E2=80=98ev= al=E2=80=99 does, I=E2=80=99d tend to put the =E2=80=98machine=E2=80=99 argument second= =E2=80=94but that=E2=80=99s a separate issue. :-)) > +(define (switch-system-program os) > + "Return as a monadic value a derivation to build a scheme file that, u= pon > +being evaluated, will create a new generation for SYSTEM-DERIVATION and > +execute ACTIVATION-SCRIPT." > + (gexp->script > + "switch-to-system.scm" > + (with-extensions (list guile-gcrypt) > + (with-imported-modules (source-module-closure '((guix config) > + (guix profiles) > + (guix utils))) > + #~(begin > + (use-modules (guix config) > + (guix profiles) > + (guix utils)) > + > + (define %system-profile > + (string-append %state-directory "/profiles/system")) > + > + (let* ((number (1+ (generation-number %system-profile))) > + (generation (generation-file-name %system-profile numb= er))) > + (switch-symlinks generation #$os) > + (switch-symlinks %system-profile generation) > + (setenv "GUIX_NEW_SYSTEM" #$os) > + (with-output-to-string > + (lambda () > + (primitive-load > + #$(operating-system-activation-script os)))))))))) Can we remove =E2=80=98with-output-to-string=E2=80=99? I=E2=80=99d rather = see what=E2=80=99s going on. :-) If that=E2=80=99s too verbose, we can use =E2=80=98invoke/quiet=E2=80=99. > +;; XXX: Currently, this does NOT attempt to restart running services. See > +;; for details. > +(define (upgrade-services-program target-services) > + "Return as a monadic value a derivation to build a scheme file that, u= pon > +being evaluated, will use TARGET-SERVICES, a list > +of (shepherd-service-canonical-name, shepherd-service-file) pairs to det= ermine > +which services are obsolete and need to be unloaded, as well as which se= rvices > +are new and need to be started." > + (gexp->script > + "upgrade-shepherd-services.scm" > + (with-imported-modules '((gnu services herd)) > + #~(begin > + (use-modules (gnu services herd) > + (srfi srfi-1)) > + > + (define running > + (filter live-service-running (current-services))) > + > + (define (essential? service) > + ;; Return #t if SERVICE is essential and should not be unloaded > + ;; under any circumstance. > + (memq (first (live-service-provision service)) > + '(root shepherd))) > + > + (define (obsolete? service) > + ;; Return #t if SERVICE can be safely unloaded. > + (and (not (essential? service)) > + (every (lambda (requirements) > + (not (memq (first (live-service-provision servic= e)) > + requirements))) > + (map live-service-requirement running)))) > + > + (define to-unload > + (filter obsolete? > + (remove (lambda (service) > + (memq (first (live-service-provision service= )) > + (map first '#$target-services))) > + running))) > + > + (define to-start > + (remove (lambda (service-pair) > + (memq (first service-pair) > + (map (compose first live-service-provision) > + running))) > + '#$target-services)) > + > + ;; Unload obsolete services. > + (for-each (lambda (service) > + (false-if-exception > + (unload-service service))) > + to-unload) > + > + ;; Load the service files for any new services and start them. > + (load-services/safe (map second to-start)) > + (for-each start-service (map first to-start)))))) It seems that this sort-of inlines parts of =E2=80=98shepherd-service-upgra= de=E2=80=99 but without traversing the service dependency graph to determine the compilete set of obsolete services, no? I feel that we should be reusing =E2=80=98shepherd-service-upgrade=E2=80=99 or similar bits. (I rea= lize this is already in =E2=80=98master=E2=80=99 for =E2=80=98guix deploy=E2=80=99, but = since this is going to be shared with =E2=80=98guix system=E2=80=99, we=E2=80=99d rather be extra cau= tious.) Also, I think we should remove =E2=80=98false-if-exception=E2=80=99 around =E2=80=98unload-service=E2=80=99. > +(define (install-bootloader-program installer-script bootcfg bootcfg-fil= e target) > + "Return as a monadic value a derivation to build a scheme file that, u= pon > +being evaluated, will install BOOTCFG to BOOTCFG-FILE, a target path, on > +TARGET, a mount point, and subsequently run INSTALLER-SCRIPT." > + (gexp->script > + "install-bootloader.scm" > + (with-extensions (list guile-gcrypt) > + (with-imported-modules (source-module-closure '((gnu build install) > + (guix store) > + (guix utils))) > + #~(begin > + (use-modules (gnu build install) > + (guix store) > + (guix utils)) > + (let* ((gc-root (string-append "/" %gc-roots-directory "/boot= cfg")) > + (temp-gc-root (string-append gc-root ".new"))) > + > + (switch-symlinks temp-gc-root gc-root) > + > + (let ((installer-result > + (false-if-exception > + (begin > + (install-boot-config #$bootcfg #$bootcfg-file #$t= arget) > + (with-output-to-string > + (lambda () > + (primitive-load #$installer-script))))))) > + (unless installer-result > + (delete-file temp-gc-root) > + (error "failed to install bootloader")) > + (rename-file temp-gc-root gc-root) > + installer-result))))))) I=E2=80=99d rather not swallow stdout and not use =E2=80=98error=E2=80=99. = Or at least, code that runs =E2=80=98install-bootloader-program=E2=80=99 should be able to pr= oduce a meaningful (and i18n=E2=80=99d) error message. So the caller could do some= thing like: (define result (machine-eval #~(=E2=80=A6 (guard (c ((message-condition? c) (cons 'error (condition-message c)))) (invoke/quiet #$(install-bootloader-program =E2=80= =A6)) '(success))) machine)) (match result (('error message) (leave (G_ "failed to install bootloader:~%~a~%") message)) (('success) #t)) Does that make sense? That=E2=80=99s quite some boilerplate to the challenge will be to factorize= it. Ultimately, the code in (guix scripts system reconfigure) should be parameterized by an evaluation procedure that would be either =E2=80=98machine-eval=E2=80=99 or some hypothetical =E2=80=98local-eval=E2= =80=99 procedure to evaluate things locally. Thanks, Ludo=E2=80=99.