;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2019 Danny Milosavljevic <dannym@scratchpost.org>
+;;; Copyright © 2019, 2020 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
#:use-module (gnu services networking)
#:use-module (gnu services docker)
#:use-module (gnu services desktop)
- #:use-module (gnu packages bootstrap) ; %bootstrap-guile
#:use-module (gnu packages docker)
+ #:use-module (gnu packages guile)
#:use-module (guix gexp)
#:use-module (guix grafts)
#:use-module (guix monads)
#:use-module (guix tests)
#:use-module (guix build-system trivial)
#:use-module ((guix licenses) #:prefix license:)
- #:export (%test-docker))
+ #:export (%test-docker
+ %test-docker-system))
(define %docker-os
(simple-operating-system
marionette))
(test-equal "Load docker image and run it"
- "hello world"
+ '("hello world" "hi!" "JSON!" #o1777)
(marionette-eval
`(begin
(define slurp
(repository&tag (string-drop raw-line
(string-length
"Loaded image: ")))
- (response (slurp
- ,(string-append #$docker-cli "/bin/docker")
- "run" "--entrypoint" "bin/Guile"
- repository&tag
- "/aa.scm")))
- response))
+ (response1 (slurp
+ ,(string-append #$docker-cli "/bin/docker")
+ "run" "--entrypoint" "bin/Guile"
+ repository&tag
+ "/aa.scm"))
+ (response2 (slurp ;default entry point
+ ,(string-append #$docker-cli "/bin/docker")
+ "run" repository&tag
+ "-c" "(display \"hi!\")"))
+
+ ;; Check whether (json) is in $GUILE_LOAD_PATH.
+ (response3 (slurp ;default entry point + environment
+ ,(string-append #$docker-cli "/bin/docker")
+ "run" repository&tag
+ "-c" "(use-modules (json))
+ (display (json-string->scm (scm->json-string \"JSON!\")))"))
+
+ ;; Check whether /tmp exists.
+ (response4 (slurp
+ ,(string-append #$docker-cli "/bin/docker")
+ "run" repository&tag "-c"
+ "(display (stat:perms (lstat \"/tmp\")))")))
+ (list response1 response2 response3
+ (string->number response4))))
marionette))
(test-end)
(version "0")
(source #f)
(build-system trivial-build-system)
- (arguments `(#:guile ,%bootstrap-guile
+ (arguments `(#:guile ,guile-3.0
#:builder
(let ((out (assoc-ref %outputs "out")))
(mkdir out)
(home-page #f)
(license license:public-domain)))
(profile (profile-derivation (packages->manifest
- (list %bootstrap-guile
+ (list guile-3.0 guile-json-3
guest-script-package))
#:hooks '()
#:locales? #f))
(tarball (docker-image "docker-pack" profile
#:symlinks '(("/bin/Guile" -> "bin/guile")
("aa.scm" -> "a.scm"))
+ #:entry-point "bin/guile"
#:localstatedir? #t)))
(run-docker-test tarball)))
(name "docker")
(description "Test Docker container of Guix.")
(value (build-tarball&run-docker-test))))
+
+\f
+(define (run-docker-system-test tarball)
+ "Load DOCKER-TARBALL as Docker image and run it in a Docker container,
+inside %DOCKER-OS."
+ (define os
+ (marionette-operating-system
+ %docker-os
+ #:imported-modules '((gnu services herd)
+ (guix combinators))))
+
+ (define vm
+ (virtual-machine
+ (operating-system os)
+ ;; FIXME: Because we're using the volatile-root setup where the root file
+ ;; system is a tmpfs overlaid over a small root file system, 'docker
+ ;; load' must be able to store the whole image into memory, hence the
+ ;; huge memory requirements. We should avoid the volatile-root setup
+ ;; instead.
+ (memory-size 3500)
+ (port-forwardings '())))
+
+ (define test
+ (with-imported-modules '((gnu build marionette)
+ (guix build utils))
+ #~(begin
+ (use-modules (srfi srfi-11) (srfi srfi-64)
+ (gnu build marionette)
+ (guix build utils))
+
+ (define marionette
+ (make-marionette (list #$vm)))
+
+ (mkdir #$output)
+ (chdir #$output)
+
+ (test-begin "docker")
+
+ (test-assert "service running"
+ (marionette-eval
+ '(begin
+ (use-modules (gnu services herd))
+ (match (start-service 'dockerd)
+ (#f #f)
+ (('service response-parts ...)
+ (match (assq-ref response-parts 'running)
+ ((pid) (number? pid))))))
+ marionette))
+
+ (test-assert "load system image and run it"
+ (marionette-eval
+ `(begin
+ (define (slurp command . args)
+ ;; Return the output from COMMAND.
+ (let* ((port (apply open-pipe* OPEN_READ command args))
+ (output (read-line port))
+ (status (close-pipe port)))
+ output))
+
+ (define (docker-cli command . args)
+ ;; Run the given Docker COMMAND.
+ (apply invoke #$(file-append docker-cli "/bin/docker")
+ command args))
+
+ (define (wait-for-container-file container file)
+ ;; Wait for FILE to show up in CONTAINER.
+ (docker-cli "exec" container
+ #$(file-append guile-3.0 "/bin/guile")
+ "-c"
+ (object->string
+ `(let loop ((n 15))
+ (when (zero? n)
+ (error "file didn't show up" ,file))
+ (unless (file-exists? ,file)
+ (sleep 1)
+ (loop (- n 1)))))))
+
+ (let* ((line (slurp #$(file-append docker-cli "/bin/docker")
+ "load" "-i" #$tarball))
+ (repository&tag (string-drop line
+ (string-length
+ "Loaded image: ")))
+ (container (slurp
+ #$(file-append docker-cli "/bin/docker")
+ "create" repository&tag)))
+ (docker-cli "start" container)
+
+ ;; Wait for shepherd to be ready.
+ (wait-for-container-file container
+ "/var/run/shepherd/socket")
+
+ (docker-cli "exec" container
+ "/run/current-system/profile/bin/herd"
+ "status")
+ (slurp #$(file-append docker-cli "/bin/docker")
+ "exec" container
+ "/run/current-system/profile/bin/herd"
+ "status" "guix-daemon")))
+ marionette))
+
+ (test-end)
+ (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
+
+ (gexp->derivation "docker-system-test" test))
+
+(define %test-docker-system
+ (system-test
+ (name "docker-system")
+ (description "Run a system image as produced by @command{guix system
+docker-image} inside Docker.")
+ (value (with-monad %store-monad
+ (>>= (system-docker-image (simple-operating-system))
+ run-docker-system-test)))))