1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2019 Danny Milosavljevic <dannym@scratchpost.org>
3 ;;; Copyright © 2019 Ludovic Courtès <ludo@gnu.org>
5 ;;; This file is part of GNU Guix.
7 ;;; GNU Guix is free software; you can redistribute it and/or modify it
8 ;;; under the terms of the GNU General Public License as published by
9 ;;; the Free Software Foundation; either version 3 of the License, or (at
10 ;;; your option) any later version.
12 ;;; GNU Guix is distributed in the hope that it will be useful, but
13 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;;; GNU General Public License for more details.
17 ;;; You should have received a copy of the GNU General Public License
18 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
20 (define-module (gnu tests docker)
21 #:use-module (gnu tests)
22 #:use-module (gnu system)
23 #:use-module (gnu system file-systems)
24 #:use-module (gnu system vm)
25 #:use-module (gnu services)
26 #:use-module (gnu services dbus)
27 #:use-module (gnu services networking)
28 #:use-module (gnu services docker)
29 #:use-module (gnu services desktop)
30 #:use-module (gnu packages docker)
31 #:use-module (gnu packages guile)
32 #:use-module (guix gexp)
33 #:use-module (guix grafts)
34 #:use-module (guix monads)
35 #:use-module (guix packages)
36 #:use-module (guix profiles)
37 #:use-module (guix scripts pack)
38 #:use-module (guix store)
39 #:use-module (guix tests)
40 #:use-module (guix build-system trivial)
41 #:use-module ((guix licenses) #:prefix license:)
42 #:export (%test-docker
46 (simple-operating-system
47 (service dhcp-client-service-type)
50 (service elogind-service-type)
51 (service docker-service-type)))
53 (define (run-docker-test docker-tarball)
54 "Load DOCKER-TARBALL as Docker image and run it in a Docker container,
57 (marionette-operating-system
59 #:imported-modules '((gnu services herd)
66 (disk-image-size (* 1500 (expt 2 20)))
67 (port-forwardings '())))
70 (with-imported-modules '((gnu build marionette))
72 (use-modules (srfi srfi-11) (srfi srfi-64)
73 (gnu build marionette))
76 (make-marionette (list #$vm)))
83 (test-assert "service running"
86 (use-modules (gnu services herd))
87 (match (start-service 'dockerd)
89 (('service response-parts ...)
90 (match (assq-ref response-parts 'running)
91 ((pid) (number? pid))))))
94 (test-eq "fetch version"
98 (system* ,(string-append #$docker-cli "/bin/docker")
102 (test-equal "Load docker image and run it"
103 '("hello world" "hi!" "JSON!")
108 (let* ((port (apply open-pipe* OPEN_READ args))
109 (output (read-line port))
110 (status (close-pipe port)))
112 (let* ((raw-line (slurp ,(string-append #$docker-cli
116 (repository&tag (string-drop raw-line
120 ,(string-append #$docker-cli "/bin/docker")
121 "run" "--entrypoint" "bin/Guile"
124 (response2 (slurp ;default entry point
125 ,(string-append #$docker-cli "/bin/docker")
127 "-c" "(display \"hi!\")"))
129 ;; Check whether (json) is in $GUILE_LOAD_PATH.
130 (response3 (slurp ;default entry point + environment
131 ,(string-append #$docker-cli "/bin/docker")
133 "-c" "(use-modules (json))
134 (display (json-string->scm (scm->json-string \"JSON!\")))")))
135 (list response1 response2 response3)))
139 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
141 (gexp->derivation "docker-test" test))
143 (define (build-tarball&run-docker-test)
145 ((_ (set-grafting #f))
146 (guile (set-guile-for-build (default-guile)))
147 (guest-script-package ->
149 (name "guest-script")
152 (build-system trivial-build-system)
153 (arguments `(#:guile ,guile-2.2
155 (let ((out (assoc-ref %outputs "out")))
157 (call-with-output-file (string-append out "/a.scm")
159 (display "(display \"hello world\n\")" port)))
161 (synopsis "Display hello world using Guile")
162 (description "This package displays the text \"hello world\" on the
163 standard output device and then enters a new line.")
165 (license license:public-domain)))
166 (profile (profile-derivation (packages->manifest
167 (list guile-2.2 guile-json
168 guest-script-package))
171 (tarball (docker-image "docker-pack" profile
172 #:symlinks '(("/bin/Guile" -> "bin/guile")
173 ("aa.scm" -> "a.scm"))
174 #:entry-point "bin/guile"
175 #:localstatedir? #t)))
176 (run-docker-test tarball)))
181 (description "Test Docker container of Guix.")
182 (value (build-tarball&run-docker-test))))
185 (define (run-docker-system-test tarball)
186 "Load DOCKER-TARBALL as Docker image and run it in a Docker container,
189 (marionette-operating-system
191 #:imported-modules '((gnu services herd)
192 (guix combinators))))
196 (operating-system os)
197 ;; FIXME: Because we're using the volatile-root setup where the root file
198 ;; system is a tmpfs overlaid over a small root file system, 'docker
199 ;; load' must be able to store the whole image into memory, hence the
200 ;; huge memory requirements. We should avoid the volatile-root setup
203 (port-forwardings '())))
206 (with-imported-modules '((gnu build marionette)
209 (use-modules (srfi srfi-11) (srfi srfi-64)
210 (gnu build marionette)
214 (make-marionette (list #$vm)))
219 (test-begin "docker")
221 (test-assert "service running"
224 (use-modules (gnu services herd))
225 (match (start-service 'dockerd)
227 (('service response-parts ...)
228 (match (assq-ref response-parts 'running)
229 ((pid) (number? pid))))))
232 (test-assert "load system image and run it"
235 (define (slurp command . args)
236 ;; Return the output from COMMAND.
237 (let* ((port (apply open-pipe* OPEN_READ command args))
238 (output (read-line port))
239 (status (close-pipe port)))
242 (define (docker-cli command . args)
243 ;; Run the given Docker COMMAND.
244 (apply invoke #$(file-append docker-cli "/bin/docker")
247 (define (wait-for-container-file container file)
248 ;; Wait for FILE to show up in CONTAINER.
249 (docker-cli "exec" container
250 #$(file-append guile-2.2 "/bin/guile")
255 (error "file didn't show up" ,file))
256 (unless (file-exists? ,file)
260 (let* ((line (slurp #$(file-append docker-cli "/bin/docker")
261 "load" "-i" #$tarball))
262 (repository&tag (string-drop line
266 #$(file-append docker-cli "/bin/docker")
267 "create" repository&tag)))
268 (docker-cli "start" container)
270 ;; Wait for shepherd to be ready.
271 (wait-for-container-file container
272 "/var/run/shepherd/socket")
274 (docker-cli "exec" container
275 "/run/current-system/profile/bin/herd"
277 (slurp #$(file-append docker-cli "/bin/docker")
279 "/run/current-system/profile/bin/herd"
280 "status" "guix-daemon")))
284 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
286 (gexp->derivation "docker-system-test" test))
288 (define %test-docker-system
290 (name "docker-system")
291 (description "Run a system image as produced by @command{guix system
292 docker-image} inside Docker.")
293 (value (with-monad %store-monad
294 (>>= (system-docker-image (simple-operating-system))
295 run-docker-system-test)))))