From e3de272a810732a7c8d226717413a6b06b716515 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Sun, 19 Jun 2016 23:53:24 +0200 Subject: tests: Export 'run-basic-test'. * gnu/tests/base.scm (run-basic-test): New procedure, extracted from ... (%test-basic-os): ... here. Use it. --- gnu/tests/base.scm | 203 +++++++++++++++++++++++++++-------------------------- 1 file changed, 105 insertions(+), 98 deletions(-) (limited to 'gnu/tests') diff --git a/gnu/tests/base.scm b/gnu/tests/base.scm index 0f19449508..ee342ed827 100644 --- a/gnu/tests/base.scm +++ b/gnu/tests/base.scm @@ -30,7 +30,8 @@ #:use-module (guix monads) #:use-module (guix packages) #:use-module (srfi srfi-1) - #:export (%test-basic-os)) + #:export (run-basic-test + %test-basic-os)) (define %simple-os (operating-system @@ -56,6 +57,108 @@ %base-user-accounts)))) +(define* (run-basic-test os command #:optional (name "basic")) + "Return a derivation called NAME that tests basic features of the OS started +using COMMAND, a gexp that evaluates to a list of strings. Compare some +properties of running system to what's declared in OS, an ." + (define test + #~(begin + (use-modules (gnu build marionette) + (srfi srfi-1) + (srfi srfi-26) + (srfi srfi-64) + (ice-9 match)) + + (define marionette + (make-marionette #$command)) + + (mkdir #$output) + (chdir #$output) + + (test-begin "basic") + + (test-assert "uname" + (match (marionette-eval '(uname) marionette) + (#("Linux" "komputilo" version _ "x86_64") + (string-prefix? #$(package-version + (operating-system-kernel os)) + version)))) + + (test-assert "shell and user commands" + ;; Is everything in $PATH? + (zero? (marionette-eval '(system " +. /etc/profile +set -e -x +guix --version +ls --version +grep --version +info --version") + marionette))) + + (test-assert "accounts" + (let ((users (marionette-eval '(begin + (use-modules (ice-9 match)) + (let loop ((result '())) + (match (getpw) + (#f (reverse result)) + (x (loop (cons x result)))))) + marionette))) + (lset= string=? + (map passwd:name users) + (list + #$@(map user-account-name + (operating-system-user-accounts os)))))) + + (test-assert "shepherd services" + (let ((services (marionette-eval '(begin + (use-modules (gnu services herd)) + (call-with-values current-services + append)) + marionette))) + (lset= eq? + (pk 'services services) + '(root #$@(operating-system-shepherd-service-names + (virtualized-operating-system os '())))))) + + (test-equal "login on tty1" + "root\n" + (begin + (marionette-control "sendkey ctrl-alt-f1" marionette) + ;; Wait for the 'term-tty1' service to be running (using + ;; 'start-service' is the simplest and most reliable way to do + ;; that.) + (marionette-eval + '(begin + (use-modules (gnu services herd)) + (start-service 'term-tty1)) + marionette) + + ;; Now we can type. + (marionette-type "root\n\nid -un > logged-in\n" marionette) + + ;; It can take a while before the shell commands are executed. + (let loop ((i 0)) + (unless (or (file-exists? "/root/logged-in") (> i 15)) + (sleep 1) + (loop (+ i 1)))) + (marionette-eval '(use-modules (rnrs io ports)) marionette) + (marionette-eval '(call-with-input-file "/root/logged-in" + get-string-all) + marionette))) + + (test-assert "screendump" + (begin + (marionette-control (string-append "screendump " #$output + "/tty1.ppm") + marionette) + (file-exists? "tty1.ppm"))) + + (test-end) + (exit (= (test-runner-fail-count (test-runner-current)) 0)))) + + (gexp->derivation name test + #:modules '((gnu build marionette)))) + (define %test-basic-os ;; Monadic derivation that instruments %SIMPLE-OS, runs it in a VM, and runs ;; a series of basic functionality tests. @@ -65,100 +168,4 @@ (guix combinators)))) (run (system-qemu-image/shared-store-script os #:graphic? #f))) - (define test - #~(begin - (use-modules (gnu build marionette) - (srfi srfi-1) - (srfi srfi-26) - (srfi srfi-64) - (ice-9 match)) - - (define marionette - (make-marionette (list #$run))) - - (mkdir #$output) - (chdir #$output) - - (test-begin "basic") - - (test-assert "uname" - (match (marionette-eval '(uname) marionette) - (#("Linux" "komputilo" version _ "x86_64") - (string-prefix? #$(package-version - (operating-system-kernel os)) - version)))) - - (test-assert "shell and user commands" - ;; Is everything in $PATH? - (zero? (marionette-eval '(system " -. /etc/profile -set -e -x -guix --version -ls --version -grep --version -info --version") - marionette))) - - (test-assert "accounts" - (let ((users (marionette-eval '(begin - (use-modules (ice-9 match)) - (let loop ((result '())) - (match (getpw) - (#f (reverse result)) - (x (loop (cons x result)))))) - marionette))) - (lset= string=? - (map passwd:name users) - (list - #$@(map user-account-name - (operating-system-user-accounts os)))))) - - (test-assert "shepherd services" - (let ((services (marionette-eval '(begin - (use-modules (gnu services herd)) - (call-with-values current-services - append)) - marionette))) - (lset= eq? - (pk 'services services) - '(root #$@(operating-system-shepherd-service-names - (virtualized-operating-system os '())))))) - - (test-equal "login on tty1" - "root\n" - (begin - (marionette-control "sendkey ctrl-alt-f1" marionette) - ;; Wait for the 'term-tty1' service to be running (using - ;; 'start-service' is the simplest and most reliable way to do - ;; that.) - (marionette-eval - '(begin - (use-modules (gnu services herd)) - (start-service 'term-tty1)) - marionette) - - ;; Now we can type. - (marionette-type "root\n\nid -un > logged-in\n" marionette) - - ;; It can take a while before the shell commands are executed. - (let loop ((i 0)) - (unless (or (file-exists? "/root/logged-in") (> i 15)) - (sleep 1) - (loop (+ i 1)))) - (marionette-eval '(use-modules (rnrs io ports)) marionette) - (marionette-eval '(call-with-input-file "/root/logged-in" - get-string-all) - marionette))) - - (test-assert "screendump" - (begin - (marionette-control (string-append "screendump " #$output - "/tty1.ppm") - marionette) - (file-exists? "tty1.ppm"))) - - (test-end) - (exit (= (test-runner-fail-count (test-runner-current)) 0)))) - - (gexp->derivation "basic" test - #:modules '((gnu build marionette))))) + (run-basic-test os #~(list #$run)))) -- cgit 1.4.1 From 908935b512c1c22839eef201ff80d0bdef093962 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 20 Jun 2016 21:39:23 +0200 Subject: tests: base: Fully honor the OS passed to 'run-basic-test'. * gnu/tests/base.scm (run-basic-test)["uname"]: Use the host name of OS. ["shepherd services"]: Use service names from OS. (%test-basic-os): Add call to 'virtualized-operating-system'. --- gnu/tests/base.scm | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'gnu/tests') diff --git a/gnu/tests/base.scm b/gnu/tests/base.scm index ee342ed827..b417bc4bda 100644 --- a/gnu/tests/base.scm +++ b/gnu/tests/base.scm @@ -79,10 +79,12 @@ properties of running system to what's declared in OS, an ." (test-assert "uname" (match (marionette-eval '(uname) marionette) - (#("Linux" "komputilo" version _ "x86_64") - (string-prefix? #$(package-version - (operating-system-kernel os)) - version)))) + (#("Linux" host-name version _ "x86_64") + (and (string=? host-name + #$(operating-system-host-name os)) + (string-prefix? #$(package-version + (operating-system-kernel os)) + version))))) (test-assert "shell and user commands" ;; Is everything in $PATH? @@ -117,8 +119,7 @@ info --version") marionette))) (lset= eq? (pk 'services services) - '(root #$@(operating-system-shepherd-service-names - (virtualized-operating-system os '())))))) + '(root #$@(operating-system-shepherd-service-names os))))) (test-equal "login on tty1" "root\n" @@ -168,4 +169,8 @@ info --version") (guix combinators)))) (run (system-qemu-image/shared-store-script os #:graphic? #f))) - (run-basic-test os #~(list #$run)))) + ;; XXX: Add call to 'virtualized-operating-system' to get the exact same + ;; set of services as the OS produced by + ;; 'system-qemu-image/shared-store-script'. + (run-basic-test (virtualized-operating-system os '()) + #~(list #$run)))) -- cgit 1.4.1 From 94b4274d0dc5768bac255980c7e785bd3dff261f Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 20 Jun 2016 21:51:59 +0200 Subject: tests: Add system installation test. * gnu/tests.scm (define-os-with-source): New macro. * gnu/tests/install.scm: New file. * gnu/local.mk (GNU_SYSTEM_MODULES): Add it. * build-aux/run-system-tests.scm (%system-tests): Likewise. --- build-aux/run-system-tests.scm | 4 +- gnu/local.mk | 3 +- gnu/tests.scm | 22 ++++- gnu/tests/install.scm | 205 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 231 insertions(+), 3 deletions(-) create mode 100644 gnu/tests/install.scm (limited to 'gnu/tests') diff --git a/build-aux/run-system-tests.scm b/build-aux/run-system-tests.scm index e98de9cb7e..4ce9b83fed 100644 --- a/build-aux/run-system-tests.scm +++ b/build-aux/run-system-tests.scm @@ -18,6 +18,7 @@ (define-module (run-system-tests) #:use-module (gnu tests base) + #:use-module (gnu tests install) #:use-module (guix store) #:use-module (guix monads) #:use-module (guix derivations) @@ -45,7 +46,8 @@ (lift1 reverse %store-monad)))) (define %system-tests - (list %test-basic-os)) + (list %test-basic-os + %test-installed-os)) (define (run-system-tests . args) (with-store store diff --git a/gnu/local.mk b/gnu/local.mk index 55fea0e855..150d6af553 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -409,7 +409,8 @@ GNU_SYSTEM_MODULES = \ %D%/build/vm.scm \ \ %D%/tests.scm \ - %D%/tests/base.scm + %D%/tests/base.scm \ + %D%/tests/install.scm patchdir = $(guilemoduledir)/%D%/packages/patches diff --git a/gnu/tests.scm b/gnu/tests.scm index 7ca80ebf0e..348b5ad40f 100644 --- a/gnu/tests.scm +++ b/gnu/tests.scm @@ -22,7 +22,8 @@ #:use-module (gnu services) #:use-module (gnu services shepherd) #:export (marionette-service-type - marionette-operating-system)) + marionette-operating-system + define-os-with-source)) ;;; Commentary: ;;; @@ -127,4 +128,23 @@ in a virtual machine--i.e., controlled from the host system." (services (cons (service marionette-service-type imported-modules) (operating-system-user-services os))))) +(define-syntax define-os-with-source + (syntax-rules (use-modules operating-system) + "Define two variables: OS containing the given operating system, and +SOURCE containing the source to define OS as an sexp. + +This is convenient when we need both the object so we can +instantiate it, and the source to create it so we can store in in a file in +the system under test." + ((_ (os source) + (use-modules modules ...) + (operating-system fields ...)) + (begin + (define os + (operating-system fields ...)) + (define source + '(begin + (use-modules modules ...) + (operating-system fields ...))))))) + ;;; tests.scm ends here diff --git a/gnu/tests/install.scm b/gnu/tests/install.scm new file mode 100644 index 0000000000..0b3950a212 --- /dev/null +++ b/gnu/tests/install.scm @@ -0,0 +1,205 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2016 Ludovic Courtès +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see . + +(define-module (gnu tests install) + #:use-module (gnu) + #:use-module (gnu tests) + #:use-module (gnu tests base) + #:use-module (gnu system) + #:use-module (gnu system install) + #:use-module (gnu system vm) + #:use-module ((gnu build vm) #:select (qemu-command)) + #:use-module (gnu packages qemu) + #:use-module (gnu packages package-management) + #:use-module (guix store) + #:use-module (guix monads) + #:use-module (guix packages) + #:use-module (guix grafts) + #:use-module (guix gexp) + #:use-module (guix utils) + #:export (%test-installed-os)) + +;;; Commentary: +;;; +;;; Test the installation of GuixSD using the documented approach at the +;;; command line. +;;; +;;; Code: + +(define-os-with-source (%minimal-os %minimal-os-source) + ;; The OS we want to install. + (use-modules (gnu) (gnu tests) (srfi srfi-1)) + + (operating-system + (host-name "liberigilo") + (timezone "Europe/Paris") + (locale "en_US.UTF-8") + + (bootloader (grub-configuration (device "/dev/vdb"))) + (kernel-arguments '("console=ttyS0")) + (file-systems (cons (file-system + (device "my-root") + (title 'label) + (mount-point "/") + (type "ext4")) + %base-file-systems)) + (users (cons (user-account + (name "alice") + (comment "Bob's sister") + (group "users") + (supplementary-groups '("wheel" "audio" "video")) + (home-directory "/home/alice")) + %base-user-accounts)) + (services (cons (service marionette-service-type + '((gnu services herd) + (guix combinators))) + %base-services)))) + +(define (operating-system-with-current-guix os) + "Return a variant of OS that uses the current Guix." + (operating-system + (inherit os) + (services (modify-services (operating-system-user-services os) + (guix-service-type config => + (guix-configuration + (inherit config) + (guix (current-guix)))))))) + +(define (operating-system-with-gc-roots os roots) + "Return a variant of OS where ROOTS are registered as GC roots." + (operating-system + (inherit os) + (services (cons (service gc-root-service-type roots) + (operating-system-user-services os))))) + + +(define MiB (expt 2 20)) + +(define* (run-install #:key + (os (marionette-operating-system + ;; Since the image has no network access, use the + ;; current Guix so the store items we need are in + ;; the image. + (operating-system + (inherit (operating-system-with-current-guix + installation-os)) + (kernel-arguments '("console=ttyS0"))) + #:imported-modules '((gnu services herd) + (guix combinators)))) + (target-size (* 1200 MiB))) + "Run the GuixSD installation procedure from OS and return a VM image of +TARGET-SIZE bytes containing the installed system." + + (mlet* %store-monad ((_ (set-grafting #f)) + (system (current-system)) + (target (operating-system-derivation %minimal-os)) + + ;; Since the installation system has no network access, + ;; we cheat a little bit by adding TARGET to its GC + ;; roots. This way, we know 'guix system init' will + ;; succeed. + (image (system-disk-image + (operating-system-with-gc-roots + os (list target)) + #:disk-image-size (* 1500 MiB)))) + (define install + #~(begin + (use-modules (guix build utils) + (gnu build marionette)) + + (set-path-environment-variable "PATH" '("bin") + (list #$qemu-minimal)) + + (system* "qemu-img" "create" "-f" "qcow2" + #$output #$(number->string target-size)) + + (define marionette + (make-marionette + (cons (which #$(qemu-command system)) + (cons* "-no-reboot" "-m" "800" + "-drive" + (string-append "file=" #$image + ",if=virtio,readonly") + "-drive" + (string-append "file=" #$output ",if=virtio") + (if (file-exists? "/dev/kvm") + '("-enable-kvm") + '()))))) + + (pk 'uname (marionette-eval '(uname) marionette)) + + ;; Wait for tty1. + (marionette-eval '(begin + (use-modules (gnu services herd)) + (start 'term-tty1)) + marionette) + + (marionette-eval '(call-with-output-file "/etc/litl-config.scm" + (lambda (port) + (write '#$%minimal-os-source port))) + marionette) + + (exit (marionette-eval '(zero? (system " +. /etc/profile +set -e -x; +guix --version +guix gc --list-live | grep isc-dhcp + +export GUIX_BUILD_OPTIONS=--no-grafts +guix build isc-dhcp +parted --script /dev/vdb mklabel gpt \\ + mkpart primary ext2 1M 3M \\ + mkpart primary ext2 3M 1G \\ + set 1 boot on \\ + set 1 bios_grub on +mkfs.ext4 -L my-root /dev/vdb2 +ls -l /dev/vdb +mount /dev/vdb2 /mnt +df -h /mnt +herd start cow-store /mnt +mkdir /mnt/etc +cp /etc/litl-config.scm /mnt/etc/config.scm +guix system init /mnt/etc/config.scm /mnt --no-substitutes +sync +reboot\n")) + marionette)))) + + (gexp->derivation "installation" install + #:modules '((guix build utils) + (gnu build marionette))))) + + +(define %test-installed-os + ;; Test basic functionality of an OS installed like one would do by hand. + ;; This test is expensive in terms of CPU and storage usage since we need to + ;; build (current-guix) and then store a couple of full system images. + (mlet %store-monad ((image (run-install)) + (system (current-system))) + (run-basic-test %minimal-os + #~(let ((image #$image)) + ;; First we need a writable copy of the image. + (format #t "copying image '~a'...~%" image) + (copy-file image "disk.img") + (chmod "disk.img" #o644) + (list (string-append #$qemu-minimal "/bin/" + #$(qemu-command system)) + "-enable-kvm" "-no-reboot" "-m" "256" + "-drive" "file=disk.img,if=virtio")) + "installed-os"))) + +;;; install.scm ends here -- cgit 1.4.1 From 98b65b5ff6b1dea0ad58b0f47dd163c32d0cbf6e Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 20 Jun 2016 22:34:13 +0200 Subject: tests: Add a mechanism to describe and discover system tests. * gnu/tests.scm (): New record type. (write-system-test, test-modules, fold-system-tests) (all-system-tests): New procedures. * gnu/tests/base.scm (%test-basic-os): Turn into a . * gnu/tests/install.scm (%test-installed-os): Likewise. * build-aux/run-system-tests.scm (%system-tests): Remove. (run-system-tests): Use 'all-system-tests'. --- Makefile.am | 1 - build-aux/run-system-tests.scm | 15 +++++----- gnu/tests.scm | 68 +++++++++++++++++++++++++++++++++++++++++- gnu/tests/base.scm | 30 +++++++++++-------- gnu/tests/install.scm | 36 ++++++++++++---------- 5 files changed, 112 insertions(+), 38 deletions(-) (limited to 'gnu/tests') diff --git a/Makefile.am b/Makefile.am index 8fd1c1b0b6..37a0aef7dc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -334,7 +334,6 @@ check-local: endif !CAN_RUN_TESTS check-system: $(GOBJECTS) - $(AM_V_at)echo "Running system tests..." $(AM_V_at)$(top_builddir)/pre-inst-env \ $(GUILE) --no-auto-compile \ -e '(@@ (run-system-tests) run-system-tests)' \ diff --git a/build-aux/run-system-tests.scm b/build-aux/run-system-tests.scm index 4ce9b83fed..f7c99def23 100644 --- a/build-aux/run-system-tests.scm +++ b/build-aux/run-system-tests.scm @@ -17,8 +17,7 @@ ;;; along with GNU Guix. If not, see . (define-module (run-system-tests) - #:use-module (gnu tests base) - #:use-module (gnu tests install) + #:use-module (gnu tests) #:use-module (guix store) #:use-module (guix monads) #:use-module (guix derivations) @@ -45,14 +44,16 @@ lst) (lift1 reverse %store-monad)))) -(define %system-tests - (list %test-basic-os - %test-installed-os)) - (define (run-system-tests . args) + (define tests + (all-system-tests)) + + (format (current-error-port) "Running ~a system tests...~%" + (length tests)) + (with-store store (run-with-store store - (mlet* %store-monad ((drv (sequence %store-monad %system-tests)) + (mlet* %store-monad ((drv (mapm %store-monad system-test-value tests)) (out -> (map derivation->output-path drv))) (mbegin %store-monad (show-what-to-build* drv) diff --git a/gnu/tests.scm b/gnu/tests.scm index 348b5ad40f..ea779ed6f0 100644 --- a/gnu/tests.scm +++ b/gnu/tests.scm @@ -18,12 +18,28 @@ (define-module (gnu tests) #:use-module (guix gexp) + #:use-module (guix utils) + #:use-module (guix records) #:use-module (gnu system) #:use-module (gnu services) #:use-module (gnu services shepherd) + #:use-module ((gnu packages) #:select (scheme-modules)) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-9 gnu) + #:use-module (ice-9 match) #:export (marionette-service-type marionette-operating-system - define-os-with-source)) + define-os-with-source + + system-test + system-test? + system-test-name + system-test-value + system-test-description + system-test-location + + fold-system-tests + all-system-tests)) ;;; Commentary: ;;; @@ -147,4 +163,54 @@ the system under test." (use-modules modules ...) (operating-system fields ...))))))) + +;;; +;;; Tests. +;;; + +(define-record-type* system-test make-system-test + system-test? + (name system-test-name) ;string + (value system-test-value) ;%STORE-MONAD value + (description system-test-description) ;string + (location system-test-location (innate) ; + (default (and=> (current-source-location) + source-properties->location)))) + +(define (write-system-test test port) + (match test + (($ name _ _ ($ file line)) + (format port "#" + name file line + (number->string (object-address test) 16))) + (($ name) + (format port "#" name + (number->string (object-address test) 16))))) + +(set-record-type-printer! write-system-test) + +(define (test-modules) + "Return the list of modules that define system tests." + (scheme-modules (dirname (search-path %load-path "guix.scm")) + "gnu/tests")) + +(define (fold-system-tests proc seed) + "Invoke PROC on each system test, passing it the test and the previous +result." + (fold (lambda (module result) + (fold (lambda (thing result) + (if (system-test? thing) + (proc thing result) + result)) + result + (module-map (lambda (sym var) + (false-if-exception (variable-ref var))) + module))) + '() + (test-modules))) + +(define (all-system-tests) + "Return the list of system tests." + (reverse (fold-system-tests cons '()))) + ;;; tests.scm ends here diff --git a/gnu/tests/base.scm b/gnu/tests/base.scm index b417bc4bda..3dfa28f7f5 100644 --- a/gnu/tests/base.scm +++ b/gnu/tests/base.scm @@ -161,16 +161,20 @@ info --version") #:modules '((gnu build marionette)))) (define %test-basic-os - ;; Monadic derivation that instruments %SIMPLE-OS, runs it in a VM, and runs - ;; a series of basic functionality tests. - (mlet* %store-monad ((os -> (marionette-operating-system - %simple-os - #:imported-modules '((gnu services herd) - (guix combinators)))) - (run (system-qemu-image/shared-store-script - os #:graphic? #f))) - ;; XXX: Add call to 'virtualized-operating-system' to get the exact same - ;; set of services as the OS produced by - ;; 'system-qemu-image/shared-store-script'. - (run-basic-test (virtualized-operating-system os '()) - #~(list #$run)))) + (system-test + (name "basic") + (description + "Instrument %SIMPLE-OS, run it in a VM, and runs a series of basic +functionality tests.") + (value + (mlet* %store-monad ((os -> (marionette-operating-system + %simple-os + #:imported-modules '((gnu services herd) + (guix combinators)))) + (run (system-qemu-image/shared-store-script + os #:graphic? #f))) + ;; XXX: Add call to 'virtualized-operating-system' to get the exact same + ;; set of services as the OS produced by + ;; 'system-qemu-image/shared-store-script'. + (run-basic-test (virtualized-operating-system os '()) + #~(list #$run)))))) diff --git a/gnu/tests/install.scm b/gnu/tests/install.scm index 0b3950a212..c33919ba2f 100644 --- a/gnu/tests/install.scm +++ b/gnu/tests/install.scm @@ -185,21 +185,25 @@ reboot\n")) (define %test-installed-os - ;; Test basic functionality of an OS installed like one would do by hand. - ;; This test is expensive in terms of CPU and storage usage since we need to - ;; build (current-guix) and then store a couple of full system images. - (mlet %store-monad ((image (run-install)) - (system (current-system))) - (run-basic-test %minimal-os - #~(let ((image #$image)) - ;; First we need a writable copy of the image. - (format #t "copying image '~a'...~%" image) - (copy-file image "disk.img") - (chmod "disk.img" #o644) - (list (string-append #$qemu-minimal "/bin/" - #$(qemu-command system)) - "-enable-kvm" "-no-reboot" "-m" "256" - "-drive" "file=disk.img,if=virtio")) - "installed-os"))) + (system-test + (name "installed-os") + (description + "Test basic functionality of an OS installed like one would do by hand. +This test is expensive in terms of CPU and storage usage since we need to +build (current-guix) and then store a couple of full system images.") + (value + (mlet %store-monad ((image (run-install)) + (system (current-system))) + (run-basic-test %minimal-os + #~(let ((image #$image)) + ;; First we need a writable copy of the image. + (format #t "copying image '~a'...~%" image) + (copy-file image "disk.img") + (chmod "disk.img" #o644) + (list (string-append #$qemu-minimal "/bin/" + #$(qemu-command system)) + "-enable-kvm" "-no-reboot" "-m" "256" + "-drive" "file=disk.img,if=virtio")) + "installed-os"))))) ;;; install.scm ends here -- cgit 1.4.1 From c311089b0b19f094e44d3f858c29f77d757332d1 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Wed, 22 Jun 2016 22:36:40 +0200 Subject: services: Add 'mcron-service'. * gnu/services/mcron.scm: New file. * gnu/local.mk (GNU_SYSTEM_MODULES): Add it. * gnu/tests/base.scm (%mcron-os, %test-mcron): New variables. (run-mcron-test): New procedure. * doc/guix.texi (Scheduled Job Execution): New node. --- doc/guix.texi | 78 +++++++++++++++++++++++++++++++++ gnu/local.mk | 1 + gnu/services/mcron.scm | 115 +++++++++++++++++++++++++++++++++++++++++++++++++ gnu/tests/base.scm | 106 ++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 299 insertions(+), 1 deletion(-) create mode 100644 gnu/services/mcron.scm (limited to 'gnu/tests') diff --git a/doc/guix.texi b/doc/guix.texi index 0bb68bb477..7516d75b8d 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -204,6 +204,7 @@ System Configuration Services * Base Services:: Essential system services. +* Scheduled Job Execution:: The mcron service. * Networking Services:: Network setup, SSH daemon, etc. * X Window:: Graphical display. * Desktop Services:: D-Bus and desktop services. @@ -7185,6 +7186,7 @@ declaration. @menu * Base Services:: Essential system services. +* Scheduled Job Execution:: The mcron service. * Networking Services:: Network setup, SSH daemon, etc. * X Window:: Graphical display. * Desktop Services:: D-Bus and desktop services. @@ -7463,6 +7465,82 @@ archive}). If that is not the case, the service will fail to start. @end deffn +@node Scheduled Job Execution +@subsubsection Scheduled Job Execution + +@cindex cron +@cindex scheduling jobs +The @code{(gnu services mcron)} module provides an interface to +GNU@tie{}mcron, a daemon to run jobs at scheduled times (@pxref{Top,,, +mcron, GNU@tie{}mcron}). GNU@tie{}mcron is similar to the traditional +Unix @command{cron} daemon; the main difference is that it is +implemented in Guile Scheme, which provides a lot of flexibility when +specifying the scheduling of jobs and their actions. + +For example, to define an operating system that runs the +@command{updatedb} (@pxref{Invoking updatedb,,, find, Finding Files}) +and the @command{guix gc} commands (@pxref{Invoking guix gc}) daily: + +@lisp +(use-modules (guix) (gnu) (gnu services mcron)) + +(define updatedb-job + ;; Run 'updatedb' at 3 AM every day. + #~(job '(next-hour '(3)) + "updatedb --prunepaths='/tmp /var/tmp /gnu/store'")) + +(define garbage-collector-job + ;; Collect garbage 5 minutes after midnight every day. + #~(job "5 0 * * *" ;Vixie cron syntax + "guix gc -F 1G")) + +(operating-system + ;; @dots{} + (services (cons (mcron-service (list garbage-collector-job + updatedb-job)) + %base-services))) +@end lisp + +@xref{Guile Syntax, mcron job specifications,, mcron, GNU@tie{}mcron}, +for more information on mcron job specifications. Below is the +reference of the mcron service. + +@deffn {Scheme Procedure} mcron-service @var{jobs} [#:mcron @var{mcron2}] +Return an mcron service running @var{mcron} that schedules @var{jobs}, a +list of gexps denoting mcron job specifications. + +This is a shorthand for: +@example + (service mcron-service-type + (mcron-configuration (mcron mcron) (jobs jobs))) +@end example +@end deffn + +@defvr {Scheme Variable} mcron-service-type +This is the type of the @code{mcron} service, whose value is an +@code{mcron-configuration} object. + +This service type can be the target of a service extension that provides +it additional job specifications (@pxref{Service Composition}). In +other words, it is possible to define services that provide addition +mcron jobs to run. +@end defvr + +@deftp {Data Type} mcron-configuration +Data type representing the configuration of mcron. + +@table @asis +@item @code{mcron} (default: @var{mcron2}) +The mcron package to use. + +@item @code{jobs} +This is a list of gexps (@pxref{G-Expressions}), where each gexp +corresponds to an mcron job specification (@pxref{Syntax, mcron job +specifications,, mcron, GNU@tie{}mcron}). +@end table +@end deftp + + @node Networking Services @subsubsection Networking Services diff --git a/gnu/local.mk b/gnu/local.mk index ab0cf49b24..3e0082b8fa 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -377,6 +377,7 @@ GNU_SYSTEM_MODULES = \ %D%/services/dict.scm \ %D%/services/lirc.scm \ %D%/services/mail.scm \ + %D%/services/mcron.scm \ %D%/services/networking.scm \ %D%/services/shepherd.scm \ %D%/services/herd.scm \ diff --git a/gnu/services/mcron.scm b/gnu/services/mcron.scm new file mode 100644 index 0000000000..313c8364f8 --- /dev/null +++ b/gnu/services/mcron.scm @@ -0,0 +1,115 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2016 Ludovic Courtès +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see . + +(define-module (gnu services mcron) + #:use-module (gnu services) + #:use-module (gnu services base) + #:use-module (gnu services shepherd) + #:autoload (gnu packages guile) (mcron2) + #:use-module (guix records) + #:use-module (guix gexp) + #:use-module (srfi srfi-1) + #:use-module (ice-9 match) + #:use-module (ice-9 vlist) + #:export (mcron-configuration + mcron-configuration? + mcron-configuration-mcron + mcron-configuration-jobs + + mcron-service-type + mcron-service)) + +;;; Commentary: +;;; +;;; This module implements a service that to run instances of GNU mcron, a +;;; periodic job execution daemon. Example of a service: +;; +;; (service mcron-service-type +;; (mcron-configuration +;; (jobs (list #~(job next-second-from +;; (lambda () +;; (call-with-output-file "/dev/console" +;; (lambda (port) +;; (display "hello!\n" port))))))))) +;;; +;;; Code: + +(define-record-type* mcron-configuration + make-mcron-configuration + mcron-configuration? + (mcron mcron-configuration-mcron ;package + (default mcron2)) + (jobs mcron-configuration-jobs ;list of + (default '()))) + +(define (job-file job) + (scheme-file "mcron-job" job)) + +(define mcron-shepherd-services + (match-lambda + (($ mcron ()) ;nothing to do! + '()) + (($ mcron jobs) + (list (shepherd-service + (provision '(mcron)) + (requirement '(user-processes)) + (modules `((srfi srfi-1) + (srfi srfi-26) + ,@%default-modules)) + (start #~(make-forkexec-constructor + (list (string-append #$mcron "/bin/mcron") + #$@(map job-file jobs)) + + ;; Disable auto-compilation of the job files and set a + ;; sane value for 'PATH'. + #:environment-variables + (cons* "GUILE_AUTO_COMPILE=0" + "PATH=/run/current-system/profile/bin" + (remove (cut string-prefix? "PATH=" <>) + (environ))))) + (stop #~(make-kill-destructor))))))) + +(define mcron-service-type + (service-type (name 'mcron) + (extensions + (list (service-extension shepherd-root-service-type + mcron-shepherd-services) + (service-extension profile-service-type + (compose list + mcron-configuration-mcron)))) + (compose concatenate) + (extend (lambda (config jobs) + (mcron-configuration + (inherit config) + (jobs (append (mcron-configuration-jobs config) + jobs))))))) + +(define* (mcron-service jobs #:optional (mcron mcron2)) + "Return an mcron service running @var{mcron} that schedules @var{jobs}, a +list of gexps denoting mcron job specifications. + +This is a shorthand for: +@example + (service mcron-service-type + (mcron-configuration (mcron mcron) (jobs jobs))) +@end example +" + (service mcron-service-type + (mcron-configuration (mcron mcron) (jobs jobs)))) + +;;; mcron.scm ends here diff --git a/gnu/tests/base.scm b/gnu/tests/base.scm index 3dfa28f7f5..8b1fefe9f8 100644 --- a/gnu/tests/base.scm +++ b/gnu/tests/base.scm @@ -24,6 +24,7 @@ #:use-module (gnu system shadow) #:use-module (gnu system vm) #:use-module (gnu services) + #:use-module (gnu services mcron) #:use-module (gnu services shepherd) #:use-module (guix gexp) #:use-module (guix store) @@ -31,7 +32,8 @@ #:use-module (guix packages) #:use-module (srfi srfi-1) #:export (run-basic-test - %test-basic-os)) + %test-basic-os + %test-mcron)) (define %simple-os (operating-system @@ -178,3 +180,105 @@ functionality tests.") ;; 'system-qemu-image/shared-store-script'. (run-basic-test (virtualized-operating-system os '()) #~(list #$run)))))) + + +;;; +;;; Mcron. +;;; + +(define %mcron-os + ;; System with an mcron service, with one mcron job for "root" and one mcron + ;; job for an unprivileged user (note: #:user is an 'mcron2' thing.) + (let ((job1 #~(job next-second-from + (lambda () + (call-with-output-file "witness" + (lambda (port) + (display (list (getuid) (getgid)) port)))))) + (job2 #~(job next-second-from + (lambda () + (call-with-output-file "witness" + (lambda (port) + (display (list (getuid) (getgid)) port)))) + #:user "alice")) + (job3 #~(job next-second-from ;to test $PATH + "touch witness-touch"))) + (operating-system + (inherit %simple-os) + (services (cons (mcron-service (list job1 job2 job3)) + (operating-system-user-services %simple-os)))))) + +(define (run-mcron-test name) + (mlet* %store-monad ((os -> (marionette-operating-system + %mcron-os + #:imported-modules '((gnu services herd) + (guix combinators)))) + (command (system-qemu-image/shared-store-script + os #:graphic? #f))) + (define test + #~(begin + (use-modules (gnu build marionette) + (srfi srfi-64) + (ice-9 match)) + + (define marionette + (make-marionette (list #$command))) + + (define (wait-for-file file) + ;; Wait until FILE exists in the guest; 'read' its content and + ;; return it. + (marionette-eval + `(let loop ((i 10)) + (cond ((file-exists? ,file) + (call-with-input-file ,file read)) + ((> i 0) + (sleep 1) + (loop (- i 1))) + (else + (error "file didn't show up" ,file)))) + marionette)) + + (mkdir #$output) + (chdir #$output) + + (test-begin "mcron") + + (test-eq "service running" + 'running! + (marionette-eval + '(begin + (use-modules (gnu services herd)) + (start-service 'mcron) + 'running!) + marionette)) + + ;; Make sure root's mcron job runs, has its cwd set to "/root", and + ;; runs with the right UID/GID. + (test-equal "root's job" + '(0 0) + (wait-for-file "/root/witness")) + + ;; Likewise for Alice's job. We cannot know what its GID is since + ;; it's chosen by 'groupadd', but it's strictly positive. + (test-assert "alice's job" + (match (wait-for-file "/home/alice/witness") + ((1000 gid) + (>= gid 100)))) + + ;; Last, the job that uses a command; allows us to test whether + ;; $PATH is sane. (Note that 'marionette-eval' stringifies objects + ;; that don't have a read syntax, hence the string.) + (test-equal "root's job with command" + "#" + (wait-for-file "/root/witness-touch")) + + (test-end) + (exit (= (test-runner-fail-count (test-runner-current)) 0)))) + + (gexp->derivation name test + #:modules '((gnu build marionette))))) + +(define %test-mcron + (system-test + (name "mcron") + (description "Make sure the mcron service works as advertised.") + (value (run-mcron-test name)))) -- cgit 1.4.1 From f6d5456b1b5b55e1ef48388271b29a2e19a646f9 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Thu, 23 Jun 2016 00:12:13 +0200 Subject: tests: Installation test no longer requires KVM. * gnu/tests/install.scm (%test-installed-os): Use '-enable-kvm' only when /dev/kvm exists. --- gnu/tests/install.scm | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'gnu/tests') diff --git a/gnu/tests/install.scm b/gnu/tests/install.scm index c33919ba2f..5d893deb4c 100644 --- a/gnu/tests/install.scm +++ b/gnu/tests/install.scm @@ -200,10 +200,13 @@ build (current-guix) and then store a couple of full system images.") (format #t "copying image '~a'...~%" image) (copy-file image "disk.img") (chmod "disk.img" #o644) - (list (string-append #$qemu-minimal "/bin/" - #$(qemu-command system)) - "-enable-kvm" "-no-reboot" "-m" "256" - "-drive" "file=disk.img,if=virtio")) + `(,(string-append #$qemu-minimal "/bin/" + #$(qemu-command system)) + ,@(if (file-exists? "/dev/kvm") + '("-enable-kvm") + '()) + "-no-reboot" "-m" "256" + "-drive" "file=disk.img,if=virtio")) "installed-os"))))) ;;; install.scm ends here -- cgit 1.4.1 From 125af57e09a00d861d4e9bf73f36a08296218f8c Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Thu, 23 Jun 2016 00:49:04 +0200 Subject: tests: basic: Don't hard-code the expected architecture name. * gnu/tests/base.scm (run-basic-test)["uname"]: Don't hard-code the architecture. --- gnu/tests/base.scm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'gnu/tests') diff --git a/gnu/tests/base.scm b/gnu/tests/base.scm index 8b1fefe9f8..4fe779802b 100644 --- a/gnu/tests/base.scm +++ b/gnu/tests/base.scm @@ -81,12 +81,13 @@ properties of running system to what's declared in OS, an ." (test-assert "uname" (match (marionette-eval '(uname) marionette) - (#("Linux" host-name version _ "x86_64") + (#("Linux" host-name version _ architecture) (and (string=? host-name #$(operating-system-host-name os)) (string-prefix? #$(package-version (operating-system-kernel os)) - version))))) + version) + (string-prefix? architecture %host-type))))) (test-assert "shell and user commands" ;; Is everything in $PATH? @@ -166,7 +167,7 @@ info --version") (system-test (name "basic") (description - "Instrument %SIMPLE-OS, run it in a VM, and runs a series of basic + "Instrument %SIMPLE-OS, run it in a VM, and run a series of basic functionality tests.") (value (mlet* %store-monad ((os -> (marionette-operating-system -- cgit 1.4.1 From 858d372c982594bf851d2b9cf82a9fa547c9651c Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 27 Jun 2016 21:03:28 +0200 Subject: tests: base: Add host name resolution tests. * gnu/tests/base.scm (run-basic-test)["host name resolution", "host not found"]: New tests. --- gnu/tests/base.scm | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'gnu/tests') diff --git a/gnu/tests/base.scm b/gnu/tests/base.scm index 4fe779802b..5786da512c 100644 --- a/gnu/tests/base.scm +++ b/gnu/tests/base.scm @@ -150,6 +150,27 @@ info --version") get-string-all) marionette))) + (test-assert "host name resolution" + (match (marionette-eval + '(begin + ;; Wait for nscd or our requests go through it. + (use-modules (gnu services herd)) + (start-service 'nscd) + + (list (getaddrinfo "localhost") + (getaddrinfo #$(operating-system-host-name os)))) + marionette) + ((((? vector?) ..1) ((? vector?) ..1)) + #t) + (x + (pk 'failure x #f)))) + + (test-equal "host not found" + #f + (marionette-eval + '(false-if-exception (getaddrinfo "does-not-exist")) + marionette)) + (test-assert "screendump" (begin (marionette-control (string-append "screendump " #$output -- cgit 1.4.1 From d2fa61bc35cd6958b5e74d4418931a584a4e6edd Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 27 Jun 2016 21:40:28 +0200 Subject: tests: Add Avahi and NSS-mDNS test. * gnu/tests/base.scm (%avahi-os): New variable. (run-nss-mdns-test): New procedure. (%test-nss-mdns): New variable. --- gnu/tests/base.scm | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 1 deletion(-) (limited to 'gnu/tests') diff --git a/gnu/tests/base.scm b/gnu/tests/base.scm index 5786da512c..0013b465b4 100644 --- a/gnu/tests/base.scm +++ b/gnu/tests/base.scm @@ -22,10 +22,15 @@ #:use-module (gnu system grub) #:use-module (gnu system file-systems) #:use-module (gnu system shadow) + #:use-module (gnu system nss) #:use-module (gnu system vm) #:use-module (gnu services) + #:use-module (gnu services base) + #:use-module (gnu services dbus) + #:use-module (gnu services avahi) #:use-module (gnu services mcron) #:use-module (gnu services shepherd) + #:use-module (gnu services networking) #:use-module (guix gexp) #:use-module (guix store) #:use-module (guix monads) @@ -33,7 +38,8 @@ #:use-module (srfi srfi-1) #:export (run-basic-test %test-basic-os - %test-mcron)) + %test-mcron + %test-nss-mdns)) (define %simple-os (operating-system @@ -304,3 +310,140 @@ functionality tests.") (name "mcron") (description "Make sure the mcron service works as advertised.") (value (run-mcron-test name)))) + + +;;; +;;; Avahi and NSS-mDNS. +;;; + +(define %avahi-os + (operating-system + (inherit %simple-os) + (name-service-switch %mdns-host-lookup-nss) + (services (cons* (avahi-service #:debug? #t) + (dbus-service) + (dhcp-client-service) ;needed for multicast + + ;; Enable heavyweight debugging output. + (modify-services (operating-system-user-services + %simple-os) + (nscd-service-type config + => (nscd-configuration + (inherit config) + (debug-level 3) + (log-file "/dev/console"))) + (syslog-service-type config + => + (plain-file + "syslog.conf" + "*.* /dev/console\n"))))))) + +(define (run-nss-mdns-test) + ;; Test resolution of '.local' names via libc. Start the marionette service + ;; *after* nscd. Failing to do that, libc will try to connect to nscd, + ;; fail, then never try again (see '__nss_not_use_nscd_hosts' in libc), + ;; leading to '.local' resolution failures. + (mlet* %store-monad ((os -> (marionette-operating-system + %avahi-os + #:requirements '(nscd) + #:imported-modules '((gnu services herd) + (guix combinators)))) + (run (system-qemu-image/shared-store-script + os #:graphic? #f))) + (define mdns-host-name + (string-append (operating-system-host-name os) + ".local")) + + (define test + #~(begin + (use-modules (gnu build marionette) + (srfi srfi-1) + (srfi srfi-64) + (ice-9 match)) + + (define marionette + (make-marionette (list #$run))) + + (mkdir #$output) + (chdir #$output) + + (test-begin "avahi") + + (test-assert "wait for services" + (marionette-eval + '(begin + (use-modules (gnu services herd)) + + (start-service 'nscd) + + ;; XXX: Work around a race condition in nscd: nscd creates its + ;; PID file before it is listening on its socket. + (let ((sock (socket PF_UNIX SOCK_STREAM 0))) + (let try () + (catch 'system-error + (lambda () + (connect sock AF_UNIX "/var/run/nscd/socket") + (close-port sock) + (format #t "nscd is ready~%")) + (lambda args + (format #t "waiting for nscd...~%") + (usleep 500000) + (try))))) + + ;; Wait for the other useful things. + (start-service 'avahi-daemon) + (start-service 'networking) + + #t) + marionette)) + + (test-equal "avahi-resolve-host-name" + 0 + (marionette-eval + '(system* + "/run/current-system/profile/bin/avahi-resolve-host-name" + "-v" #$mdns-host-name) + marionette)) + + (test-equal "avahi-browse" + 0 + (marionette-eval + '(system* "avahi-browse" "-avt") + marionette)) + + (test-assert "getaddrinfo .local" + ;; Wait for the 'avahi-daemon' service and perform a resolution. + (match (marionette-eval + '(getaddrinfo #$mdns-host-name) + marionette) + (((? vector? addrinfos) ..1) + (pk 'getaddrinfo addrinfos) + (and (any (lambda (ai) + (= AF_INET (addrinfo:fam ai))) + addrinfos) + (any (lambda (ai) + (= AF_INET6 (addrinfo:fam ai))) + addrinfos))))) + + (test-assert "gethostbyname .local" + (match (pk 'gethostbyname + (marionette-eval '(gethostbyname #$mdns-host-name) + marionette)) + ((? vector? result) + (and (string=? (hostent:name result) #$mdns-host-name) + (= (hostent:addrtype result) AF_INET))))) + + + (test-end) + (exit (= (test-runner-fail-count (test-runner-current)) 0)))) + + (gexp->derivation "nss-mdns" test + #:modules '((gnu build marionette))))) + +(define %test-nss-mdns + (system-test + (name "nss-mdns") + (description + "Test Avahi's multicast-DNS implementation, and in particular, test its +glibc name service switch (NSS) module.") + (value (run-nss-mdns-test)))) -- cgit 1.4.1 From a4bbf41b255bc55fac32669e8359bfe0b037b2d5 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Sat, 2 Jul 2016 12:33:52 +0200 Subject: tests: install: Adjust to new 'marionette-service-type' interface. This is a followup to 037f9e07cd03d6894a6b5fc9a252c34d3b163962. Reported by Mark H Weaver. * gnu/tests/install.scm (%minimal-os): Pass a object as the value for the MARIONETTE-SERVICE-TYPE. --- gnu/tests/install.scm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'gnu/tests') diff --git a/gnu/tests/install.scm b/gnu/tests/install.scm index 5d893deb4c..2c0db41d69 100644 --- a/gnu/tests/install.scm +++ b/gnu/tests/install.scm @@ -66,8 +66,9 @@ (home-directory "/home/alice")) %base-user-accounts)) (services (cons (service marionette-service-type - '((gnu services herd) - (guix combinators))) + (marionette-configuration + (imported-modules '((gnu services herd) + (guix combinators))))) %base-services)))) (define (operating-system-with-current-guix os) -- cgit 1.4.1 From 4ee96a7912eef8c41c855c680f924dcdba2d9c97 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Sun, 3 Jul 2016 23:11:40 +0200 Subject: gnu: Switch to 'with-imported-modules'. * gnu/services.scm (directory-union): Use 'with-imported-modules' instead of the '#:modules' argument of 'computed-file'. * gnu/services/base.scm (udev-rules-union): Likewise. * gnu/services/dbus.scm (system-service-directory): Likewise. * gnu/services/desktop.scm (wrapped-dbus-service): (polkit-directory): Likewise. * gnu/services/networking.scm (tor-configuration->torrc): Likewise. * gnu/services/xorg.scm (xorg-configuration-directory): Likewise. * gnu/system/install.scm (self-contained-tarball): Likewise. * gnu/system/linux-container.scm (container-script): Likewise. * gnu/system/linux-initrd.scm (expression->initrd): Likewise, and remove #:modules parameter. (flat-linux-module-directory): Use 'with-imported-modules'. (base-initrd): Likewise. * gnu/system/locale.scm (locale-directory): Likewise. * gnu/system/shadow.scm (default-skeletons): Likewise. * gnu/system/vm.scm (expression->derivation-in-linux-vm): Likewise. * gnu/tests/base.scm (run-basic-test): Likewise. * gnu/tests/install.scm (run-install): Likewise. * doc/guix.texi (Initial RAM Disk): Update 'expression->initrd' documentation. --- doc/guix.texi | 6 +- gnu/services.scm | 8 +- gnu/services/base.scm | 60 ++--- gnu/services/dbus.scm | 41 ++-- gnu/services/desktop.scm | 67 +++--- gnu/services/networking.scm | 54 ++--- gnu/services/xorg.scm | 42 ++-- gnu/system/install.scm | 117 +++++----- gnu/system/linux-container.scm | 48 ++-- gnu/system/linux-initrd.scm | 170 +++++++------- gnu/system/locale.scm | 8 +- gnu/system/shadow.scm | 72 +++--- gnu/system/vm.scm | 46 ++-- gnu/tests/base.scm | 514 ++++++++++++++++++++--------------------- gnu/tests/install.scm | 82 +++---- 15 files changed, 665 insertions(+), 670 deletions(-) (limited to 'gnu/tests') diff --git a/doc/guix.texi b/doc/guix.texi index b315325034..a0014e7112 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -10016,15 +10016,11 @@ program. That gives a lot of flexibility. The program to run in that initrd. @deffn {Monadic Procedure} expression->initrd @var{exp} @ - [#:guile %guile-static-stripped] [#:name "guile-initrd"] @ - [#:modules '()] + [#:guile %guile-static-stripped] [#:name "guile-initrd"] Return a derivation that builds a Linux initrd (a gzipped cpio archive) containing @var{guile} and that evaluates @var{exp}, a G-expression, upon booting. All the derivations referenced by @var{exp} are automatically copied to the initrd. - -@var{modules} is a list of Guile module names to be embedded in the -initrd. @end deffn @node GRUB Configuration diff --git a/gnu/services.scm b/gnu/services.scm index 50e76df818..661835f68e 100644 --- a/gnu/services.scm +++ b/gnu/services.scm @@ -309,10 +309,10 @@ file." one) (_ (computed-file name - #~(begin - (use-modules (guix build union)) - (union-build #$output '#$things)) - #:modules '((guix build union)))))) + (with-imported-modules '((guix build union)) + #~(begin + (use-modules (guix build union)) + (union-build #$output '#$things))))))) (define* (activation-service->script service) "Return as a monadic value the activation script for SERVICE, a service of diff --git a/gnu/services/base.scm b/gnu/services/base.scm index 5eabfec423..d9c60778a1 100644 --- a/gnu/services/base.scm +++ b/gnu/services/base.scm @@ -1138,44 +1138,44 @@ archive}). If that is not the case, the service will fail to start." "Return the union of the @code{lib/udev/rules.d} directories found in each item of @var{packages}." (define build - #~(begin - (use-modules (guix build union) - (guix build utils) - (srfi srfi-1) - (srfi srfi-26)) + (with-imported-modules '((guix build union) + (guix build utils)) + #~(begin + (use-modules (guix build union) + (guix build utils) + (srfi srfi-1) + (srfi srfi-26)) - (define %standard-locations - '("/lib/udev/rules.d" "/libexec/udev/rules.d")) + (define %standard-locations + '("/lib/udev/rules.d" "/libexec/udev/rules.d")) - (define (rules-sub-directory directory) - ;; Return the sub-directory of DIRECTORY containing udev rules, or - ;; #f if none was found. - (find directory-exists? - (map (cut string-append directory <>) %standard-locations))) + (define (rules-sub-directory directory) + ;; Return the sub-directory of DIRECTORY containing udev rules, or + ;; #f if none was found. + (find directory-exists? + (map (cut string-append directory <>) %standard-locations))) - (mkdir-p (string-append #$output "/lib/udev")) - (union-build (string-append #$output "/lib/udev/rules.d") - (filter-map rules-sub-directory '#$packages)))) + (mkdir-p (string-append #$output "/lib/udev")) + (union-build (string-append #$output "/lib/udev/rules.d") + (filter-map rules-sub-directory '#$packages))))) - (computed-file "udev-rules" build - #:modules '((guix build union) - (guix build utils)))) + (computed-file "udev-rules" build)) (define (udev-rule file-name contents) "Return a directory with a udev rule file FILE-NAME containing CONTENTS." (computed-file file-name - #~(begin - (use-modules (guix build utils)) - - (define rules.d - (string-append #$output "/lib/udev/rules.d")) - - (mkdir-p rules.d) - (call-with-output-file - (string-append rules.d "/" #$file-name) - (lambda (port) - (display #$contents port)))) - #:modules '((guix build utils)))) + (with-imported-modules '((guix build utils)) + #~(begin + (use-modules (guix build utils)) + + (define rules.d + (string-append #$output "/lib/udev/rules.d")) + + (mkdir-p rules.d) + (call-with-output-file + (string-append rules.d "/" #$file-name) + (lambda (port) + (display #$contents port))))))) (define kvm-udev-rule ;; Return a directory with a udev rule that changes the group of /dev/kvm to diff --git a/gnu/services/dbus.scm b/gnu/services/dbus.scm index 9a4a13d41d..d06b2dde23 100644 --- a/gnu/services/dbus.scm +++ b/gnu/services/dbus.scm @@ -46,26 +46,27 @@ "Return the system service directory, containing @code{.service} files for all the services that may be activated by the daemon." (computed-file "dbus-system-services" - #~(begin - (use-modules (guix build utils) - (srfi srfi-1)) - - (define files - (append-map (lambda (service) - (find-files (string-append - service - "/share/dbus-1/system-services") - "\\.service$")) - (list #$@services))) - - (mkdir #$output) - (for-each (lambda (file) - (symlink file - (string-append #$output "/" - (basename file)))) - files) - #t) - #:modules '((guix build utils)))) + (with-imported-modules '((guix build utils)) + #~(begin + (use-modules (guix build utils) + (srfi srfi-1)) + + (define files + (append-map (lambda (service) + (find-files + (string-append + service + "/share/dbus-1/system-services") + "\\.service$")) + (list #$@services))) + + (mkdir #$output) + (for-each (lambda (file) + (symlink file + (string-append #$output "/" + (basename file)))) + files) + #t)))) (define (dbus-configuration-directory services) "Return a directory contains the @code{system-local.conf} file for DBUS that diff --git a/gnu/services/desktop.scm b/gnu/services/desktop.scm index 2fb08cd1b3..86214a73bf 100644 --- a/gnu/services/desktop.scm +++ b/gnu/services/desktop.scm @@ -91,30 +91,33 @@ is set to @var{value} when the bus daemon launches it." (string-append #$service "/" #$program) (cdr (command-line)))))) + (define build + (with-imported-modules '((guix build utils)) + #~(begin + (use-modules (guix build utils)) + + (define service-directory + "/share/dbus-1/system-services") + + (mkdir-p (dirname (string-append #$output + service-directory))) + (copy-recursively (string-append #$service + service-directory) + (string-append #$output + service-directory)) + (symlink (string-append #$service "/etc") ;for etc/dbus-1 + (string-append #$output "/etc")) + + (for-each (lambda (file) + (substitute* file + (("Exec[[:blank:]]*=[[:blank:]]*([[:graph:]]+)(.*)$" + _ original-program arguments) + (string-append "Exec=" #$wrapper arguments + "\n")))) + (find-files #$output "\\.service$"))))) + (computed-file (string-append (package-name service) "-wrapper") - #~(begin - (use-modules (guix build utils)) - - (define service-directory - "/share/dbus-1/system-services") - - (mkdir-p (dirname (string-append #$output - service-directory))) - (copy-recursively (string-append #$service - service-directory) - (string-append #$output - service-directory)) - (symlink (string-append #$service "/etc") ;for etc/dbus-1 - (string-append #$output "/etc")) - - (for-each (lambda (file) - (substitute* file - (("Exec[[:blank:]]*=[[:blank:]]*([[:graph:]]+)(.*)$" - _ original-program arguments) - (string-append "Exec=" #$wrapper arguments - "\n")))) - (find-files #$output "\\.service$"))) - #:modules '((guix build utils)))) + build)) ;;; @@ -408,15 +411,15 @@ Users need to be in the @code{lp} group to access the D-Bus service. (define (polkit-directory packages) "Return a directory containing an @file{actions} and possibly a @file{rules.d} sub-directory, for use as @file{/etc/polkit-1}." - (computed-file "etc-polkit-1" - #~(begin - (use-modules (guix build union) (srfi srfi-26)) - - (union-build #$output - (map (cut string-append <> - "/share/polkit-1") - (list #$@packages)))) - #:modules '((guix build union)))) + (with-imported-modules '((guix build union)) + (computed-file "etc-polkit-1" + #~(begin + (use-modules (guix build union) (srfi srfi-26)) + + (union-build #$output + (map (cut string-append <> + "/share/polkit-1") + (list #$@packages))))))) (define polkit-etc-files (match-lambda diff --git a/gnu/services/networking.scm b/gnu/services/networking.scm index af2a60936b..a77ed3bb80 100644 --- a/gnu/services/networking.scm +++ b/gnu/services/networking.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2013, 2014, 2015 Ludovic Courtès +;;; Copyright © 2013, 2014, 2015, 2016 Ludovic Courtès ;;; Copyright © 2015 Mark H Weaver ;;; Copyright © 2016 Efraim Flashner ;;; @@ -345,39 +345,39 @@ keep the system clock synchronized with that of @var{servers}." (($ tor config-file services) (computed-file "torrc" - #~(begin - (use-modules (guix build utils) - (ice-9 match)) - - (call-with-output-file #$output - (lambda (port) - (display "\ + (with-imported-modules '((guix build utils)) + #~(begin + (use-modules (guix build utils) + (ice-9 match)) + + (call-with-output-file #$output + (lambda (port) + (display "\ # The beginning was automatically added. User tor DataDirectory /var/lib/tor Log notice syslog\n" port) - (for-each (match-lambda - ((service (ports hosts) ...) - (format port "\ + (for-each (match-lambda + ((service (ports hosts) ...) + (format port "\ HiddenServiceDir /var/lib/tor/hidden-services/~a~%" - service) - (for-each (lambda (tcp-port host) - (format port "\ + service) + (for-each (lambda (tcp-port host) + (format port "\ HiddenServicePort ~a ~a~%" - tcp-port host)) - ports hosts))) - '#$(map (match-lambda - (($ name mapping) - (cons name mapping))) - services)) - - ;; Append the user's config file. - (call-with-input-file #$config-file - (lambda (input) - (dump-port input port))) - #t))) - #:modules '((guix build utils)))))) + tcp-port host)) + ports hosts))) + '#$(map (match-lambda + (($ name mapping) + (cons name mapping))) + services)) + + ;; Append the user's config file. + (call-with-input-file #$config-file + (lambda (input) + (dump-port input port))) + #t)))))))) (define (tor-shepherd-service config) "Return a running TOR." diff --git a/gnu/services/xorg.scm b/gnu/services/xorg.scm index 9908b9526b..44d12a7e77 100644 --- a/gnu/services/xorg.scm +++ b/gnu/services/xorg.scm @@ -158,27 +158,27 @@ EndSection "Return a directory that contains the @code{.conf} files for X.org that includes the @code{share/X11/xorg.conf.d} directories of each package listed in @var{modules}." - (computed-file "xorg.conf.d" - #~(begin - (use-modules (guix build utils) - (srfi srfi-1)) - - (define files - (append-map (lambda (module) - (find-files (string-append - module - "/share/X11/xorg.conf.d") - "\\.conf$")) - (list #$@modules))) - - (mkdir #$output) - (for-each (lambda (file) - (symlink file - (string-append #$output "/" - (basename file)))) - files) - #t) - #:modules '((guix build utils)))) + (with-imported-modules '((guix build utils)) + (computed-file "xorg.conf.d" + #~(begin + (use-modules (guix build utils) + (srfi srfi-1)) + + (define files + (append-map (lambda (module) + (find-files (string-append + module + "/share/X11/xorg.conf.d") + "\\.conf$")) + (list #$@modules))) + + (mkdir #$output) + (for-each (lambda (file) + (symlink file + (string-append #$output "/" + (basename file)))) + files) + #t)))) (define* (xorg-start-command #:key (guile (canonical-package guile-2.0)) diff --git a/gnu/system/install.scm b/gnu/system/install.scm index de14f6fb4c..329c7aba32 100644 --- a/gnu/system/install.scm +++ b/gnu/system/install.scm @@ -55,52 +55,53 @@ under /root/.guix-profile where GUIX is installed." (manifest (list (package->manifest-entry guix)))))) (define build - #~(begin - (use-modules (guix build utils) - (gnu build install)) - - (define %root "root") - - (setenv "PATH" - (string-append #$guix "/sbin:" #$tar "/bin:" #$xz "/bin")) - - ;; Note: there is not much to gain here with deduplication and there - ;; is the overhead of the '.links' directory, so turn it off. - (populate-single-profile-directory %root - #:profile #$profile - #:closure "profile" - #:deduplicate? #f) - - ;; Create the tarball. Use GNU format so there's no file name - ;; length limitation. - (with-directory-excursion %root - (zero? (system* "tar" "--xz" "--format=gnu" - - ;; Avoid non-determinism in the archive. Use - ;; mtime = 1, not zero, because that is what the - ;; daemon does for files in the store (see the - ;; 'mtimeStore' constant in local-store.cc.) - "--sort=name" - "--mtime=@1" ;for files in /var/guix - "--owner=root:0" - "--group=root:0" - - "--check-links" - "-cvf" #$output - ;; Avoid adding / and /var to the tarball, - ;; so that the ownership and permissions of those - ;; directories will not be overwritten when - ;; extracting the archive. Do not include /root - ;; because the root account might have a different - ;; home directory. - "./var/guix" - (string-append "." (%store-directory))))))) + (with-imported-modules '((guix build utils) + (guix build store-copy) + (gnu build install)) + #~(begin + (use-modules (guix build utils) + (gnu build install)) + + (define %root "root") + + (setenv "PATH" + (string-append #$guix "/sbin:" #$tar "/bin:" #$xz "/bin")) + + ;; Note: there is not much to gain here with deduplication and + ;; there is the overhead of the '.links' directory, so turn it + ;; off. + (populate-single-profile-directory %root + #:profile #$profile + #:closure "profile" + #:deduplicate? #f) + + ;; Create the tarball. Use GNU format so there's no file name + ;; length limitation. + (with-directory-excursion %root + (zero? (system* "tar" "--xz" "--format=gnu" + + ;; Avoid non-determinism in the archive. Use + ;; mtime = 1, not zero, because that is what the + ;; daemon does for files in the store (see the + ;; 'mtimeStore' constant in local-store.cc.) + "--sort=name" + "--mtime=@1" ;for files in /var/guix + "--owner=root:0" + "--group=root:0" + + "--check-links" + "-cvf" #$output + ;; Avoid adding / and /var to the tarball, so + ;; that the ownership and permissions of those + ;; directories will not be overwritten when + ;; extracting the archive. Do not include /root + ;; because the root account might have a + ;; different home directory. + "./var/guix" + (string-append "." (%store-directory)))))))) (gexp->derivation "guix-tarball.tar.xz" build - #:references-graphs `(("profile" ,profile)) - #:modules '((guix build utils) - (guix build store-copy) - (gnu build install))))) + #:references-graphs `(("profile" ,profile))))) (define (log-to-info) @@ -212,20 +213,20 @@ the user's target storage device rather than on the RAM disk." (define directory (computed-file "configuration-templates" - #~(begin - (mkdir #$output) - (for-each (lambda (file target) - (copy-file file - (string-append #$output "/" - target))) - '(#$(file "bare-bones.tmpl") - #$(file "desktop.tmpl") - #$(file "lightweight-desktop.tmpl")) - '("bare-bones.scm" - "desktop.scm" - "lightweight-desktop.scm")) - #t) - #:modules '((guix build utils)))) + (with-imported-modules '((guix build utils)) + #~(begin + (mkdir #$output) + (for-each (lambda (file target) + (copy-file file + (string-append #$output "/" + target))) + '(#$(file "bare-bones.tmpl") + #$(file "desktop.tmpl") + #$(file "lightweight-desktop.tmpl")) + '("bare-bones.scm" + "desktop.scm" + "lightweight-desktop.scm")) + #t)))) `(("configuration" ,directory))) diff --git a/gnu/system/linux-container.scm b/gnu/system/linux-container.scm index 3acc579a6b..2e20379473 100644 --- a/gnu/system/linux-container.scm +++ b/gnu/system/linux-container.scm @@ -87,30 +87,28 @@ that will be shared with the host system." #:container? #t))) (define script - #~(begin - (use-modules (gnu build linux-container) - (guix build utils)) + (with-imported-modules '((guix config) + (guix utils) + (guix build utils) + (guix build syscalls) + (guix build bournish) + (gnu build file-systems) + (gnu build linux-container)) + #~(begin + (use-modules (gnu build linux-container) + (guix build utils)) - (call-with-container '#$specs - (lambda () - (setenv "HOME" "/root") - (setenv "TMPDIR" "/tmp") - (setenv "GUIX_NEW_SYSTEM" #$os-drv) - (for-each mkdir-p '("/run" "/bin" "/etc" "/home" "/var")) - (primitive-load (string-append #$os-drv "/boot"))) - ;; A range of 65536 uid/gids is used to cover 16 bits worth of - ;; users and groups, which is sufficient for most cases. - ;; - ;; See: http://www.freedesktop.org/software/systemd/man/systemd-nspawn.html#--private-users= - #:host-uids 65536))) + (call-with-container '#$specs + (lambda () + (setenv "HOME" "/root") + (setenv "TMPDIR" "/tmp") + (setenv "GUIX_NEW_SYSTEM" #$os-drv) + (for-each mkdir-p '("/run" "/bin" "/etc" "/home" "/var")) + (primitive-load (string-append #$os-drv "/boot"))) + ;; A range of 65536 uid/gids is used to cover 16 bits worth of + ;; users and groups, which is sufficient for most cases. + ;; + ;; See: http://www.freedesktop.org/software/systemd/man/systemd-nspawn.html#--private-users= + #:host-uids 65536)))) - (gexp->script "run-container" script - #:modules '((ice-9 match) - (srfi srfi-98) - (guix config) - (guix utils) - (guix build utils) - (guix build syscalls) - (guix build bournish) - (gnu build file-systems) - (gnu build linux-container)))))) + (gexp->script "run-container" script)))) diff --git a/gnu/system/linux-initrd.scm b/gnu/system/linux-initrd.scm index 8339fae7ed..bbaa5c0f89 100644 --- a/gnu/system/linux-initrd.scm +++ b/gnu/system/linux-initrd.scm @@ -55,85 +55,81 @@ (guile %guile-static-stripped) (gzip gzip) (name "guile-initrd") - (system (%current-system)) - (modules '())) + (system (%current-system))) "Return a derivation that builds a Linux initrd (a gzipped cpio archive) containing GUILE and that evaluates EXP, a G-expression, upon booting. All -the derivations referenced by EXP are automatically copied to the initrd. - -MODULES is a list of Guile module names to be embedded in the initrd." +the derivations referenced by EXP are automatically copied to the initrd." ;; General Linux overview in `Documentation/early-userspace/README' and ;; `Documentation/filesystems/ramfs-rootfs-initramfs.txt'. (mlet %store-monad ((init (gexp->script "init" exp - #:modules modules #:guile guile))) (define builder - #~(begin - (use-modules (gnu build linux-initrd)) + (with-imported-modules '((guix cpio) + (guix build utils) + (guix build store-copy) + (gnu build linux-initrd)) + #~(begin + (use-modules (gnu build linux-initrd)) - (mkdir #$output) - (build-initrd (string-append #$output "/initrd") - #:guile #$guile - #:init #$init - ;; Copy everything INIT refers to into the initrd. - #:references-graphs '("closure") - #:gzip (string-append #$gzip "/bin/gzip")))) + (mkdir #$output) + (build-initrd (string-append #$output "/initrd") + #:guile #$guile + #:init #$init + ;; Copy everything INIT refers to into the initrd. + #:references-graphs '("closure") + #:gzip (string-append #$gzip "/bin/gzip"))))) - (gexp->derivation name builder - #:modules '((guix cpio) - (guix build utils) - (guix build store-copy) - (gnu build linux-initrd)) - #:references-graphs `(("closure" ,init))))) + (gexp->derivation name builder + #:references-graphs `(("closure" ,init))))) (define (flat-linux-module-directory linux modules) "Return a flat directory containing the Linux kernel modules listed in MODULES and taken from LINUX." (define build-exp - #~(begin - (use-modules (ice-9 match) (ice-9 regex) - (srfi srfi-1) - (guix build utils) - (gnu build linux-modules)) + (with-imported-modules '((guix build utils) + (guix elf) + (gnu build linux-modules)) + #~(begin + (use-modules (ice-9 match) (ice-9 regex) + (srfi srfi-1) + (guix build utils) + (gnu build linux-modules)) - (define (string->regexp str) - ;; Return a regexp that matches STR exactly. - (string-append "^" (regexp-quote str) "$")) + (define (string->regexp str) + ;; Return a regexp that matches STR exactly. + (string-append "^" (regexp-quote str) "$")) - (define module-dir - (string-append #$linux "/lib/modules")) + (define module-dir + (string-append #$linux "/lib/modules")) - (define (lookup module) - (let ((name (ensure-dot-ko module))) - (match (find-files module-dir (string->regexp name)) - ((file) - file) - (() - (error "module not found" name module-dir)) - ((_ ...) - (error "several modules by that name" - name module-dir))))) + (define (lookup module) + (let ((name (ensure-dot-ko module))) + (match (find-files module-dir (string->regexp name)) + ((file) + file) + (() + (error "module not found" name module-dir)) + ((_ ...) + (error "several modules by that name" + name module-dir))))) - (define modules - (let ((modules (map lookup '#$modules))) - (append modules - (recursive-module-dependencies modules - #:lookup-module lookup)))) + (define modules + (let ((modules (map lookup '#$modules))) + (append modules + (recursive-module-dependencies modules + #:lookup-module lookup)))) - (mkdir #$output) - (for-each (lambda (module) - (format #t "copying '~a'...~%" module) - (copy-file module - (string-append #$output "/" - (basename module)))) - (delete-duplicates modules)))) + (mkdir #$output) + (for-each (lambda (module) + (format #t "copying '~a'...~%" module) + (copy-file module + (string-append #$output "/" + (basename module)))) + (delete-duplicates modules))))) - (gexp->derivation "linux-modules" build-exp - #:modules '((guix build utils) - (guix elf) - (gnu build linux-modules)))) + (gexp->derivation "linux-modules" build-exp)) (define* (base-initrd file-systems #:key @@ -227,38 +223,38 @@ loaded at boot time in the order in which they appear." (mlet %store-monad ((kodir (flat-linux-module-directory linux linux-modules))) (expression->initrd - #~(begin - (use-modules (gnu build linux-boot) - (guix build utils) - (guix build bournish) ;add the 'bournish' meta-command - (srfi srfi-26) + (with-imported-modules '((guix build bournish) + (guix build utils) + (guix build syscalls) + (gnu build linux-boot) + (gnu build linux-modules) + (gnu build file-systems) + (guix elf)) + #~(begin + (use-modules (gnu build linux-boot) + (guix build utils) + (guix build bournish) ;add the 'bournish' meta-command + (srfi srfi-26) - ;; FIXME: The following modules are for - ;; LUKS-DEVICE-MAPPING. We should instead propagate - ;; this info via gexps. - ((gnu build file-systems) - #:select (find-partition-by-luks-uuid)) - (rnrs bytevectors)) + ;; FIXME: The following modules are for + ;; LUKS-DEVICE-MAPPING. We should instead propagate + ;; this info via gexps. + ((gnu build file-systems) + #:select (find-partition-by-luks-uuid)) + (rnrs bytevectors)) - (with-output-to-port (%make-void-port "w") - (lambda () - (set-path-environment-variable "PATH" '("bin" "sbin") - '#$helper-packages))) + (with-output-to-port (%make-void-port "w") + (lambda () + (set-path-environment-variable "PATH" '("bin" "sbin") + '#$helper-packages))) - (boot-system #:mounts '#$(map file-system->spec file-systems) - #:pre-mount (lambda () - (and #$@device-mapping-commands)) - #:linux-modules '#$linux-modules - #:linux-module-directory '#$kodir - #:qemu-guest-networking? #$qemu-networking? - #:volatile-root? '#$volatile-root?)) - #:name "base-initrd" - #:modules '((guix build bournish) - (guix build utils) - (guix build syscalls) - (gnu build linux-boot) - (gnu build linux-modules) - (gnu build file-systems) - (guix elf))))) + (boot-system #:mounts '#$(map file-system->spec file-systems) + #:pre-mount (lambda () + (and #$@device-mapping-commands)) + #:linux-modules '#$linux-modules + #:linux-module-directory '#$kodir + #:qemu-guest-networking? #$qemu-networking? + #:volatile-root? '#$volatile-root?))) + #:name "base-initrd"))) ;;; linux-initrd.scm ends here diff --git a/gnu/system/locale.scm b/gnu/system/locale.scm index f9d713e0cf..3bb9f950a8 100644 --- a/gnu/system/locale.scm +++ b/gnu/system/locale.scm @@ -154,10 +154,10 @@ data format changes between libc versions." #:libc libc)) libcs))) (gexp->derivation "locale-multiple-versions" - #~(begin - (use-modules (guix build union)) - (union-build #$output (list #$@dirs))) - #:modules '((guix build union)) + (with-imported-modules '((guix build union)) + #~(begin + (use-modules (guix build union)) + (union-build #$output (list #$@dirs)))) #:local-build? #t #:substitutable? #f))))) diff --git a/gnu/system/shadow.scm b/gnu/system/shadow.scm index b8837c63f0..730a9ee091 100644 --- a/gnu/system/shadow.scm +++ b/gnu/system/shadow.scm @@ -139,10 +139,11 @@ `(fontconfig (dir "/run/current-system/profile/share/fonts"))) (define copy-guile-wm - #~(begin - (use-modules (guix build utils)) - (copy-file (car (find-files #$guile-wm "wm-init-sample.scm")) - #$output))) + (with-imported-modules '((guix build utils)) + #~(begin + (use-modules (guix build utils)) + (copy-file (car (find-files #$guile-wm "wm-init-sample.scm")) + #$output)))) (let ((profile (plain-file "bash_profile" "\ # Honor per-interactive-shell startup file @@ -176,27 +177,26 @@ alias ll='ls -l'\n")) (zlogin (plain-file "zlogin" "\ # Honor system-wide environment variables source /etc/profile\n")) - (guile-wm (computed-file "guile-wm" copy-guile-wm - #:modules '((guix build utils)))) + (guile-wm (computed-file "guile-wm" copy-guile-wm)) (xdefaults (plain-file "Xdefaults" "\ XTerm*utf8: always XTerm*metaSendsEscape: true\n")) (fonts.conf (computed-file "fonts.conf" - #~(begin - (use-modules (guix build utils) - (sxml simple)) - - (define dir - (string-append #$output - "/fontconfig")) - - (mkdir-p dir) - (call-with-output-file (string-append dir - "/fonts.conf") - (lambda (port) - (sxml->xml '#$fonts.conf-content port)))) - #:modules '((guix build utils)))) + (with-imported-modules '((guix build utils)) + #~(begin + (use-modules (guix build utils) + (sxml simple)) + + (define dir + (string-append #$output + "/fontconfig")) + + (mkdir-p dir) + (call-with-output-file (string-append dir + "/fonts.conf") + (lambda (port) + (sxml->xml '#$fonts.conf-content port))))))) (gdbinit (plain-file "gdbinit" "\ # Tell GDB where to look for separate debugging files. set debug-file-directory ~/.guix-profile/lib/debug\n"))) @@ -211,22 +211,22 @@ set debug-file-directory ~/.guix-profile/lib/debug\n"))) (define (skeleton-directory skeletons) "Return a directory containing SKELETONS, a list of name/derivation tuples." (computed-file "skel" - #~(begin - (use-modules (ice-9 match) - (guix build utils)) - - (mkdir #$output) - (chdir #$output) - - ;; Note: copy the skeletons instead of symlinking - ;; them like 'file-union' does, because 'useradd' - ;; would just copy the symlinks as is. - (for-each (match-lambda - ((target source) - (copy-recursively source target))) - '#$skeletons) - #t) - #:modules '((guix build utils)))) + (with-imported-modules '((guix build utils)) + #~(begin + (use-modules (ice-9 match) + (guix build utils)) + + (mkdir #$output) + (chdir #$output) + + ;; Note: copy the skeletons instead of symlinking + ;; them like 'file-union' does, because 'useradd' + ;; would just copy the symlinks as is. + (for-each (match-lambda + ((target source) + (copy-recursively source target))) + '#$skeletons) + #t)))) (define (assert-valid-users/groups users groups) "Raise an error if USERS refer to groups not listed in GROUPS." diff --git a/gnu/system/vm.scm b/gnu/system/vm.scm index 676e89df98..fc5eaf5706 100644 --- a/gnu/system/vm.scm +++ b/gnu/system/vm.scm @@ -155,34 +155,34 @@ made available under the /xchg CIFS share." (define builder ;; Code that launches the VM that evaluates EXP. - #~(begin - (use-modules (guix build utils) - (gnu build vm)) - - (let ((inputs '#$(list qemu coreutils)) - (linux (string-append #$linux "/bzImage")) - (initrd (string-append #$initrd "/initrd")) - (loader #$loader) - (graphs '#$(match references-graphs - (((graph-files . _) ...) graph-files) - (_ #f)))) - - (set-path-environment-variable "PATH" '("bin") inputs) - - (load-in-linux-vm loader - #:output #$output - #:linux linux #:initrd initrd - #:memory-size #$memory-size - #:make-disk-image? #$make-disk-image? - #:disk-image-format #$disk-image-format - #:disk-image-size #$disk-image-size - #:references-graphs graphs)))) + (with-imported-modules modules + #~(begin + (use-modules (guix build utils) + (gnu build vm)) + + (let ((inputs '#$(list qemu coreutils)) + (linux (string-append #$linux "/bzImage")) + (initrd (string-append #$initrd "/initrd")) + (loader #$loader) + (graphs '#$(match references-graphs + (((graph-files . _) ...) graph-files) + (_ #f)))) + + (set-path-environment-variable "PATH" '("bin") inputs) + + (load-in-linux-vm loader + #:output #$output + #:linux linux #:initrd initrd + #:memory-size #$memory-size + #:make-disk-image? #$make-disk-image? + #:disk-image-format #$disk-image-format + #:disk-image-size #$disk-image-size + #:references-graphs graphs))))) (gexp->derivation name builder ;; TODO: Require the "kvm" feature. #:system system #:env-vars env-vars - #:modules modules #:guile-for-build guile-for-build #:references-graphs references-graphs))) diff --git a/gnu/tests/base.scm b/gnu/tests/base.scm index 0013b465b4..a6278b25d4 100644 --- a/gnu/tests/base.scm +++ b/gnu/tests/base.scm @@ -70,125 +70,125 @@ using COMMAND, a gexp that evaluates to a list of strings. Compare some properties of running system to what's declared in OS, an ." (define test - #~(begin - (use-modules (gnu build marionette) - (srfi srfi-1) - (srfi srfi-26) - (srfi srfi-64) - (ice-9 match)) - - (define marionette - (make-marionette #$command)) - - (mkdir #$output) - (chdir #$output) - - (test-begin "basic") - - (test-assert "uname" - (match (marionette-eval '(uname) marionette) - (#("Linux" host-name version _ architecture) - (and (string=? host-name - #$(operating-system-host-name os)) - (string-prefix? #$(package-version - (operating-system-kernel os)) - version) - (string-prefix? architecture %host-type))))) - - (test-assert "shell and user commands" - ;; Is everything in $PATH? - (zero? (marionette-eval '(system " + (with-imported-modules '((gnu build marionette)) + #~(begin + (use-modules (gnu build marionette) + (srfi srfi-1) + (srfi srfi-26) + (srfi srfi-64) + (ice-9 match)) + + (define marionette + (make-marionette #$command)) + + (mkdir #$output) + (chdir #$output) + + (test-begin "basic") + + (test-assert "uname" + (match (marionette-eval '(uname) marionette) + (#("Linux" host-name version _ architecture) + (and (string=? host-name + #$(operating-system-host-name os)) + (string-prefix? #$(package-version + (operating-system-kernel os)) + version) + (string-prefix? architecture %host-type))))) + + (test-assert "shell and user commands" + ;; Is everything in $PATH? + (zero? (marionette-eval '(system " . /etc/profile set -e -x guix --version ls --version grep --version info --version") - marionette))) - - (test-assert "accounts" - (let ((users (marionette-eval '(begin - (use-modules (ice-9 match)) - (let loop ((result '())) - (match (getpw) - (#f (reverse result)) - (x (loop (cons x result)))))) - marionette))) - (lset= string=? - (map passwd:name users) - (list - #$@(map user-account-name - (operating-system-user-accounts os)))))) - - (test-assert "shepherd services" - (let ((services (marionette-eval '(begin - (use-modules (gnu services herd)) - (call-with-values current-services - append)) - marionette))) - (lset= eq? - (pk 'services services) - '(root #$@(operating-system-shepherd-service-names os))))) - - (test-equal "login on tty1" - "root\n" - (begin - (marionette-control "sendkey ctrl-alt-f1" marionette) - ;; Wait for the 'term-tty1' service to be running (using - ;; 'start-service' is the simplest and most reliable way to do - ;; that.) + marionette))) + + (test-assert "accounts" + (let ((users (marionette-eval '(begin + (use-modules (ice-9 match)) + (let loop ((result '())) + (match (getpw) + (#f (reverse result)) + (x (loop (cons x result)))))) + marionette))) + (lset= string=? + (map passwd:name users) + (list + #$@(map user-account-name + (operating-system-user-accounts os)))))) + + (test-assert "shepherd services" + (let ((services (marionette-eval '(begin + (use-modules (gnu services herd)) + (call-with-values current-services + append)) + marionette))) + (lset= eq? + (pk 'services services) + '(root #$@(operating-system-shepherd-service-names os))))) + + (test-equal "login on tty1" + "root\n" + (begin + (marionette-control "sendkey ctrl-alt-f1" marionette) + ;; Wait for the 'term-tty1' service to be running (using + ;; 'start-service' is the simplest and most reliable way to do + ;; that.) + (marionette-eval + '(begin + (use-modules (gnu services herd)) + (start-service 'term-tty1)) + marionette) + + ;; Now we can type. + (marionette-type "root\n\nid -un > logged-in\n" marionette) + + ;; It can take a while before the shell commands are executed. + (let loop ((i 0)) + (unless (or (file-exists? "/root/logged-in") (> i 15)) + (sleep 1) + (loop (+ i 1)))) + (marionette-eval '(use-modules (rnrs io ports)) marionette) + (marionette-eval '(call-with-input-file "/root/logged-in" + get-string-all) + marionette))) + + (test-assert "host name resolution" + (match (marionette-eval + '(begin + ;; Wait for nscd or our requests go through it. + (use-modules (gnu services herd)) + (start-service 'nscd) + + (list (getaddrinfo "localhost") + (getaddrinfo #$(operating-system-host-name os)))) + marionette) + ((((? vector?) ..1) ((? vector?) ..1)) + #t) + (x + (pk 'failure x #f)))) + + (test-equal "host not found" + #f (marionette-eval - '(begin - (use-modules (gnu services herd)) - (start-service 'term-tty1)) - marionette) - - ;; Now we can type. - (marionette-type "root\n\nid -un > logged-in\n" marionette) - - ;; It can take a while before the shell commands are executed. - (let loop ((i 0)) - (unless (or (file-exists? "/root/logged-in") (> i 15)) - (sleep 1) - (loop (+ i 1)))) - (marionette-eval '(use-modules (rnrs io ports)) marionette) - (marionette-eval '(call-with-input-file "/root/logged-in" - get-string-all) - marionette))) - - (test-assert "host name resolution" - (match (marionette-eval - '(begin - ;; Wait for nscd or our requests go through it. - (use-modules (gnu services herd)) - (start-service 'nscd) - - (list (getaddrinfo "localhost") - (getaddrinfo #$(operating-system-host-name os)))) - marionette) - ((((? vector?) ..1) ((? vector?) ..1)) - #t) - (x - (pk 'failure x #f)))) - - (test-equal "host not found" - #f - (marionette-eval - '(false-if-exception (getaddrinfo "does-not-exist")) - marionette)) - - (test-assert "screendump" - (begin - (marionette-control (string-append "screendump " #$output - "/tty1.ppm") - marionette) - (file-exists? "tty1.ppm"))) - - (test-end) - (exit (= (test-runner-fail-count (test-runner-current)) 0)))) - - (gexp->derivation name test - #:modules '((gnu build marionette)))) + '(false-if-exception (getaddrinfo "does-not-exist")) + marionette)) + + (test-assert "screendump" + (begin + (marionette-control (string-append "screendump " #$output + "/tty1.ppm") + marionette) + (file-exists? "tty1.ppm"))) + + (test-end) + (exit (= (test-runner-fail-count (test-runner-current)) 0))))) + + (gexp->derivation name test)) (define %test-basic-os (system-test @@ -243,67 +243,67 @@ functionality tests.") (command (system-qemu-image/shared-store-script os #:graphic? #f))) (define test - #~(begin - (use-modules (gnu build marionette) - (srfi srfi-64) - (ice-9 match)) - - (define marionette - (make-marionette (list #$command))) - - (define (wait-for-file file) - ;; Wait until FILE exists in the guest; 'read' its content and - ;; return it. - (marionette-eval - `(let loop ((i 10)) - (cond ((file-exists? ,file) - (call-with-input-file ,file read)) - ((> i 0) - (sleep 1) - (loop (- i 1))) - (else - (error "file didn't show up" ,file)))) - marionette)) - - (mkdir #$output) - (chdir #$output) - - (test-begin "mcron") - - (test-eq "service running" - 'running! - (marionette-eval - '(begin - (use-modules (gnu services herd)) - (start-service 'mcron) - 'running!) - marionette)) - - ;; Make sure root's mcron job runs, has its cwd set to "/root", and - ;; runs with the right UID/GID. - (test-equal "root's job" - '(0 0) - (wait-for-file "/root/witness")) - - ;; Likewise for Alice's job. We cannot know what its GID is since - ;; it's chosen by 'groupadd', but it's strictly positive. - (test-assert "alice's job" - (match (wait-for-file "/home/alice/witness") - ((1000 gid) - (>= gid 100)))) - - ;; Last, the job that uses a command; allows us to test whether - ;; $PATH is sane. (Note that 'marionette-eval' stringifies objects - ;; that don't have a read syntax, hence the string.) - (test-equal "root's job with command" - "#" - (wait-for-file "/root/witness-touch")) - - (test-end) - (exit (= (test-runner-fail-count (test-runner-current)) 0)))) - - (gexp->derivation name test - #:modules '((gnu build marionette))))) + (with-imported-modules '((gnu build marionette)) + #~(begin + (use-modules (gnu build marionette) + (srfi srfi-64) + (ice-9 match)) + + (define marionette + (make-marionette (list #$command))) + + (define (wait-for-file file) + ;; Wait until FILE exists in the guest; 'read' its content and + ;; return it. + (marionette-eval + `(let loop ((i 10)) + (cond ((file-exists? ,file) + (call-with-input-file ,file read)) + ((> i 0) + (sleep 1) + (loop (- i 1))) + (else + (error "file didn't show up" ,file)))) + marionette)) + + (mkdir #$output) + (chdir #$output) + + (test-begin "mcron") + + (test-eq "service running" + 'running! + (marionette-eval + '(begin + (use-modules (gnu services herd)) + (start-service 'mcron) + 'running!) + marionette)) + + ;; Make sure root's mcron job runs, has its cwd set to "/root", and + ;; runs with the right UID/GID. + (test-equal "root's job" + '(0 0) + (wait-for-file "/root/witness")) + + ;; Likewise for Alice's job. We cannot know what its GID is since + ;; it's chosen by 'groupadd', but it's strictly positive. + (test-assert "alice's job" + (match (wait-for-file "/home/alice/witness") + ((1000 gid) + (>= gid 100)))) + + ;; Last, the job that uses a command; allows us to test whether + ;; $PATH is sane. (Note that 'marionette-eval' stringifies objects + ;; that don't have a read syntax, hence the string.) + (test-equal "root's job with command" + "#" + (wait-for-file "/root/witness-touch")) + + (test-end) + (exit (= (test-runner-fail-count (test-runner-current)) 0))))) + + (gexp->derivation name test))) (define %test-mcron (system-test @@ -355,90 +355,90 @@ functionality tests.") ".local")) (define test - #~(begin - (use-modules (gnu build marionette) - (srfi srfi-1) - (srfi srfi-64) - (ice-9 match)) - - (define marionette - (make-marionette (list #$run))) - - (mkdir #$output) - (chdir #$output) - - (test-begin "avahi") - - (test-assert "wait for services" - (marionette-eval - '(begin - (use-modules (gnu services herd)) - - (start-service 'nscd) - - ;; XXX: Work around a race condition in nscd: nscd creates its - ;; PID file before it is listening on its socket. - (let ((sock (socket PF_UNIX SOCK_STREAM 0))) - (let try () - (catch 'system-error - (lambda () - (connect sock AF_UNIX "/var/run/nscd/socket") - (close-port sock) - (format #t "nscd is ready~%")) - (lambda args - (format #t "waiting for nscd...~%") - (usleep 500000) - (try))))) - - ;; Wait for the other useful things. - (start-service 'avahi-daemon) - (start-service 'networking) - - #t) - marionette)) - - (test-equal "avahi-resolve-host-name" - 0 - (marionette-eval - '(system* - "/run/current-system/profile/bin/avahi-resolve-host-name" - "-v" #$mdns-host-name) - marionette)) - - (test-equal "avahi-browse" - 0 - (marionette-eval - '(system* "avahi-browse" "-avt") - marionette)) - - (test-assert "getaddrinfo .local" - ;; Wait for the 'avahi-daemon' service and perform a resolution. - (match (marionette-eval - '(getaddrinfo #$mdns-host-name) - marionette) - (((? vector? addrinfos) ..1) - (pk 'getaddrinfo addrinfos) - (and (any (lambda (ai) - (= AF_INET (addrinfo:fam ai))) - addrinfos) - (any (lambda (ai) - (= AF_INET6 (addrinfo:fam ai))) - addrinfos))))) - - (test-assert "gethostbyname .local" - (match (pk 'gethostbyname - (marionette-eval '(gethostbyname #$mdns-host-name) - marionette)) - ((? vector? result) - (and (string=? (hostent:name result) #$mdns-host-name) - (= (hostent:addrtype result) AF_INET))))) - - - (test-end) - (exit (= (test-runner-fail-count (test-runner-current)) 0)))) - - (gexp->derivation "nss-mdns" test - #:modules '((gnu build marionette))))) + (with-imported-modules '((gnu build marionette)) + #~(begin + (use-modules (gnu build marionette) + (srfi srfi-1) + (srfi srfi-64) + (ice-9 match)) + + (define marionette + (make-marionette (list #$run))) + + (mkdir #$output) + (chdir #$output) + + (test-begin "avahi") + + (test-assert "wait for services" + (marionette-eval + '(begin + (use-modules (gnu services herd)) + + (start-service 'nscd) + + ;; XXX: Work around a race condition in nscd: nscd creates its + ;; PID file before it is listening on its socket. + (let ((sock (socket PF_UNIX SOCK_STREAM 0))) + (let try () + (catch 'system-error + (lambda () + (connect sock AF_UNIX "/var/run/nscd/socket") + (close-port sock) + (format #t "nscd is ready~%")) + (lambda args + (format #t "waiting for nscd...~%") + (usleep 500000) + (try))))) + + ;; Wait for the other useful things. + (start-service 'avahi-daemon) + (start-service 'networking) + + #t) + marionette)) + + (test-equal "avahi-resolve-host-name" + 0 + (marionette-eval + '(system* + "/run/current-system/profile/bin/avahi-resolve-host-name" + "-v" #$mdns-host-name) + marionette)) + + (test-equal "avahi-browse" + 0 + (marionette-eval + '(system* "avahi-browse" "-avt") + marionette)) + + (test-assert "getaddrinfo .local" + ;; Wait for the 'avahi-daemon' service and perform a resolution. + (match (marionette-eval + '(getaddrinfo #$mdns-host-name) + marionette) + (((? vector? addrinfos) ..1) + (pk 'getaddrinfo addrinfos) + (and (any (lambda (ai) + (= AF_INET (addrinfo:fam ai))) + addrinfos) + (any (lambda (ai) + (= AF_INET6 (addrinfo:fam ai))) + addrinfos))))) + + (test-assert "gethostbyname .local" + (match (pk 'gethostbyname + (marionette-eval '(gethostbyname #$mdns-host-name) + marionette)) + ((? vector? result) + (and (string=? (hostent:name result) #$mdns-host-name) + (= (hostent:addrtype result) AF_INET))))) + + + (test-end) + (exit (= (test-runner-fail-count (test-runner-current)) 0))))) + + (gexp->derivation "nss-mdns" test))) (define %test-nss-mdns (system-test diff --git a/gnu/tests/install.scm b/gnu/tests/install.scm index 2c0db41d69..3c83da151a 100644 --- a/gnu/tests/install.scm +++ b/gnu/tests/install.scm @@ -119,43 +119,45 @@ TARGET-SIZE bytes containing the installed system." os (list target)) #:disk-image-size (* 1500 MiB)))) (define install - #~(begin - (use-modules (guix build utils) - (gnu build marionette)) - - (set-path-environment-variable "PATH" '("bin") - (list #$qemu-minimal)) - - (system* "qemu-img" "create" "-f" "qcow2" - #$output #$(number->string target-size)) - - (define marionette - (make-marionette - (cons (which #$(qemu-command system)) - (cons* "-no-reboot" "-m" "800" - "-drive" - (string-append "file=" #$image - ",if=virtio,readonly") - "-drive" - (string-append "file=" #$output ",if=virtio") - (if (file-exists? "/dev/kvm") - '("-enable-kvm") - '()))))) - - (pk 'uname (marionette-eval '(uname) marionette)) - - ;; Wait for tty1. - (marionette-eval '(begin - (use-modules (gnu services herd)) - (start 'term-tty1)) - marionette) - - (marionette-eval '(call-with-output-file "/etc/litl-config.scm" - (lambda (port) - (write '#$%minimal-os-source port))) - marionette) - - (exit (marionette-eval '(zero? (system " + (with-imported-modules '((guix build utils) + (gnu build marionette)) + #~(begin + (use-modules (guix build utils) + (gnu build marionette)) + + (set-path-environment-variable "PATH" '("bin") + (list #$qemu-minimal)) + + (system* "qemu-img" "create" "-f" "qcow2" + #$output #$(number->string target-size)) + + (define marionette + (make-marionette + (cons (which #$(qemu-command system)) + (cons* "-no-reboot" "-m" "800" + "-drive" + (string-append "file=" #$image + ",if=virtio,readonly") + "-drive" + (string-append "file=" #$output ",if=virtio") + (if (file-exists? "/dev/kvm") + '("-enable-kvm") + '()))))) + + (pk 'uname (marionette-eval '(uname) marionette)) + + ;; Wait for tty1. + (marionette-eval '(begin + (use-modules (gnu services herd)) + (start 'term-tty1)) + marionette) + + (marionette-eval '(call-with-output-file "/etc/litl-config.scm" + (lambda (port) + (write '#$%minimal-os-source port))) + marionette) + + (exit (marionette-eval '(zero? (system " . /etc/profile set -e -x; guix --version @@ -178,11 +180,9 @@ cp /etc/litl-config.scm /mnt/etc/config.scm guix system init /mnt/etc/config.scm /mnt --no-substitutes sync reboot\n")) - marionette)))) + marionette))))) - (gexp->derivation "installation" install - #:modules '((guix build utils) - (gnu build marionette))))) + (gexp->derivation "installation" install))) (define %test-installed-os -- cgit 1.4.1 From b1bf155ffd9b160afdf05aff39d3f0b0f6d11589 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 18 Jul 2016 00:53:58 +0200 Subject: tests: install: Generalize 'run-install'. * gnu/tests/install.scm (%simple-installation-script): New variable. Contains installation script formerly in 'run-install'. (run-install): Add 'target-os', 'target-os-source', and #:script parameters. Honor them. (qemu-command/writable-image): New procedure. (%test-installed-os): Use it. --- gnu/tests/install.scm | 169 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 130 insertions(+), 39 deletions(-) (limited to 'gnu/tests') diff --git a/gnu/tests/install.scm b/gnu/tests/install.scm index 3c83da151a..4e79fdb294 100644 --- a/gnu/tests/install.scm +++ b/gnu/tests/install.scm @@ -32,7 +32,8 @@ #:use-module (guix grafts) #:use-module (guix gexp) #:use-module (guix utils) - #:export (%test-installed-os)) + #:export (%test-installed-os + %test-encrypted-os)) ;;; Commentary: ;;; @@ -91,7 +92,33 @@ (define MiB (expt 2 20)) -(define* (run-install #:key +(define %simple-installation-script + ;; Shell script of a simple installation. + "\ +. /etc/profile +set -e -x +guix --version + +export GUIX_BUILD_OPTIONS=--no-grafts +guix build isc-dhcp +parted --script /dev/vdb mklabel gpt \\ + mkpart primary ext2 1M 3M \\ + mkpart primary ext2 3M 1G \\ + set 1 boot on \\ + set 1 bios_grub on +mkfs.ext4 -L my-root /dev/vdb2 +mount /dev/vdb2 /mnt +df -h /mnt +herd start cow-store /mnt +mkdir /mnt/etc +cp /etc/target-config.scm /mnt/etc/config.scm +guix system init /mnt/etc/config.scm /mnt --no-substitutes +sync +reboot\n") + +(define* (run-install target-os target-os-source + #:key + (script %simple-installation-script) (os (marionette-operating-system ;; Since the image has no network access, use the ;; current Guix so the store items we need are in @@ -103,12 +130,13 @@ #:imported-modules '((gnu services herd) (guix combinators)))) (target-size (* 1200 MiB))) - "Run the GuixSD installation procedure from OS and return a VM image of -TARGET-SIZE bytes containing the installed system." + "Run SCRIPT (a shell script following the GuixSD installation procedure) in +OS to install TARGET-OS. Return a VM image of TARGET-SIZE bytes containing +the installed system." (mlet* %store-monad ((_ (set-grafting #f)) (system (current-system)) - (target (operating-system-derivation %minimal-os)) + (target (operating-system-derivation target-os)) ;; Since the installation system has no network access, ;; we cheat a little bit by adding TARGET to its GC @@ -152,62 +180,125 @@ TARGET-SIZE bytes containing the installed system." (start 'term-tty1)) marionette) - (marionette-eval '(call-with-output-file "/etc/litl-config.scm" + (marionette-eval '(call-with-output-file "/etc/target-config.scm" (lambda (port) - (write '#$%minimal-os-source port))) + (write '#$target-os-source port))) marionette) - (exit (marionette-eval '(zero? (system " + (exit (marionette-eval '(zero? (system #$script)) + marionette))))) + + (gexp->derivation "installation" install))) + +(define (qemu-command/writable-image image) + "Return as a monadic value the command to run QEMU on a writable copy of +IMAGE, a disk image." + (mlet %store-monad ((system (current-system))) + (return #~(let ((image #$image)) + ;; First we need a writable copy of the image. + (format #t "copying image '~a'...~%" image) + (copy-file image "disk.img") + (chmod "disk.img" #o644) + `(,(string-append #$qemu-minimal "/bin/" + #$(qemu-command system)) + ,@(if (file-exists? "/dev/kvm") + '("-enable-kvm") + '()) + "-no-reboot" "-m" "256" + "-drive" "file=disk.img,if=virtio"))))) + + +(define %test-installed-os + (system-test + (name "installed-os") + (description + "Test basic functionality of an OS installed like one would do by hand. +This test is expensive in terms of CPU and storage usage since we need to +build (current-guix) and then store a couple of full system images.") + (value + (mlet* %store-monad ((image (run-install %minimal-os %minimal-os-source)) + (command (qemu-command/writable-image image))) + (run-basic-test %minimal-os command + "installed-os"))))) + + +(define-os-with-source (%encrypted-root-os %encrypted-root-os-source) + ;; The OS we want to install. + (use-modules (gnu) (gnu tests) (srfi srfi-1)) + + (operating-system + (host-name "liberigilo") + (timezone "Europe/Paris") + (locale "en_US.UTF-8") + + (bootloader (grub-configuration (device "/dev/vdb"))) + (kernel-arguments '("console=ttyS0")) + (file-systems (cons (file-system + (device "/dev/mapper/the-root-device") + (title 'device) + (mount-point "/") + (type "ext4")) + %base-file-systems)) + (mapped-devices (list (mapped-device + (source "REPLACE-WITH-LUKS-UUID") + (target "the-root-device") + (type luks-device-mapping)))) + (users (cons (user-account + (name "charlie") + (group "users") + (home-directory "/home/charlie") + (supplementary-groups '("wheel" "audio" "video"))) + %base-user-accounts)) + (services (cons (service marionette-service-type + (marionette-configuration + (imported-modules '((gnu services herd) + (guix combinators))))) + %base-services)))) + +(define %encrypted-root-installation-script + ;; Shell script of a simple installation. + "\ . /etc/profile -set -e -x; +set -e -x guix --version -guix gc --list-live | grep isc-dhcp export GUIX_BUILD_OPTIONS=--no-grafts -guix build isc-dhcp +ls -l /run/current-system/gc-roots parted --script /dev/vdb mklabel gpt \\ mkpart primary ext2 1M 3M \\ mkpart primary ext2 3M 1G \\ set 1 boot on \\ set 1 bios_grub on -mkfs.ext4 -L my-root /dev/vdb2 -ls -l /dev/vdb -mount /dev/vdb2 /mnt -df -h /mnt +echo -n thepassphrase | cryptsetup luksFormat -q /dev/vdb2 - +echo -n thepassphrase | \\ + cryptsetup open --type luks --key-file - /dev/vdb2 the-root-device +mkfs.ext4 -L my-root /dev/mapper/the-root-device +mount LABEL=my-root /mnt herd start cow-store /mnt mkdir /mnt/etc -cp /etc/litl-config.scm /mnt/etc/config.scm +cp /etc/target-config.scm /mnt/etc/config.scm +cat /mnt/etc/config +luks_uuid=`cryptsetup luksUUID /dev/vdb2` +sed -i /mnt/etc/config.scm \\ + -e \"s/\\\"REPLACE-WITH-LUKS-UUID\\\"/(uuid \\\"$luks_uuid\\\")/g\" +guix system build /mnt/etc/config.scm guix system init /mnt/etc/config.scm /mnt --no-substitutes sync -reboot\n")) - marionette))))) - - (gexp->derivation "installation" install))) +reboot\n") - -(define %test-installed-os +(define %test-encrypted-os (system-test - (name "installed-os") + (name "encrypted-root-os") (description "Test basic functionality of an OS installed like one would do by hand. This test is expensive in terms of CPU and storage usage since we need to build (current-guix) and then store a couple of full system images.") (value - (mlet %store-monad ((image (run-install)) - (system (current-system))) - (run-basic-test %minimal-os - #~(let ((image #$image)) - ;; First we need a writable copy of the image. - (format #t "copying image '~a'...~%" image) - (copy-file image "disk.img") - (chmod "disk.img" #o644) - `(,(string-append #$qemu-minimal "/bin/" - #$(qemu-command system)) - ,@(if (file-exists? "/dev/kvm") - '("-enable-kvm") - '()) - "-no-reboot" "-m" "256" - "-drive" "file=disk.img,if=virtio")) - "installed-os"))))) + (mlet* %store-monad ((image (run-install %encrypted-root-os + %encrypted-root-os-source + #:script + %encrypted-root-installation-script)) + (command (qemu-command/writable-image image))) + (run-basic-test %encrypted-root-os command "encrypted-root-os"))))) ;;; install.scm ends here -- cgit 1.4.1