summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorDavid Thompson <davet@gnu.org>2015-06-02 08:48:16 -0400
committerDavid Thompson <dthompson2@worcester.edu>2015-07-09 08:23:03 -0400
commitc1f6a0c2ed8caa5b04aae77e5d2e3a2299305a43 (patch)
treee9641afa1af47836057b6fc9d18f10c88da92ace /tests
parent85c3127fa9226ff9efa504dddffcf8442f54488d (diff)
gnu: build: Add Linux container module.
* gnu/build/linux-container.scm: New file. * gnu-system.am (GNU_SYSTEM_MODULES): Add it. * .dir-locals.el: Add Scheme indent rules for 'call-with-container', and 'container-excursion'. * tests/containers.scm: New file. * Makefile.am (SCM_TESTS): Add it.
Diffstat (limited to 'tests')
-rw-r--r--tests/containers.scm136
1 files changed, 136 insertions, 0 deletions
diff --git a/tests/containers.scm b/tests/containers.scm
new file mode 100644
index 0000000000..43401a5f4d
--- /dev/null
+++ b/tests/containers.scm
@@ -0,0 +1,136 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2015 David Thompson <davet@gnu.org>
+;;;
+;;; 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 <http://www.gnu.org/licenses/>.
+
+(define-module (test-containers)
+ #:use-module (guix utils)
+ #:use-module (guix build syscalls)
+ #:use-module (gnu build linux-container)
+ #:use-module (srfi srfi-64)
+ #:use-module (ice-9 match))
+
+(define (assert-exit x)
+ (primitive-exit (if x 0 1)))
+
+(test-begin "containers")
+
+(test-assert "call-with-container, user namespace"
+ (zero?
+ (call-with-container '()
+ (lambda ()
+ ;; The user is root within the new user namespace.
+ (assert-exit (and (zero? (getuid)) (zero? (getgid)))))
+ #:namespaces '(user))))
+
+(test-assert "call-with-container, uts namespace"
+ (zero?
+ (call-with-container '()
+ (lambda ()
+ ;; The user is root within the container and should be able to change
+ ;; the hostname of that container.
+ (sethostname "test-container")
+ (primitive-exit 0))
+ #:namespaces '(user uts))))
+
+(test-assert "call-with-container, pid namespace"
+ (zero?
+ (call-with-container '()
+ (lambda ()
+ (match (primitive-fork)
+ (0
+ ;; The first forked process in the new pid namespace is pid 2.
+ (assert-exit (= 2 (getpid))))
+ (pid
+ (primitive-exit
+ (match (waitpid pid)
+ ((_ . status)
+ (status:exit-val status)))))))
+ #:namespaces '(user pid))))
+
+(test-assert "call-with-container, mnt namespace"
+ (zero?
+ (call-with-container '(("none" device "/testing" "tmpfs" () #f #f))
+ (lambda ()
+ (assert-exit (file-exists? "/testing")))
+ #:namespaces '(user mnt))))
+
+(test-assert "call-with-container, all namespaces"
+ (zero?
+ (call-with-container '()
+ (lambda ()
+ (primitive-exit 0)))))
+
+(test-assert "container-excursion"
+ (call-with-temporary-directory
+ (lambda (root)
+ ;; Two pipes: One for the container to signal that the test can begin,
+ ;; and one for the parent to signal to the container that the test is
+ ;; over.
+ (match (list (pipe) (pipe))
+ (((start-in . start-out) (end-in . end-out))
+ (define (container)
+ (close end-out)
+ (close start-in)
+ ;; Signal for the test to start.
+ (write 'ready start-out)
+ (close start-out)
+ ;; Wait for test completion.
+ (read end-in)
+ (close end-in))
+
+ (define (namespaces pid)
+ (let ((pid (number->string pid)))
+ (map (lambda (ns)
+ (readlink (string-append "/proc/" pid "/ns/" ns)))
+ '("user" "ipc" "uts" "net" "pid" "mnt"))))
+
+ (let* ((pid (run-container root '() %namespaces container))
+ (container-namespaces (namespaces pid))
+ (result
+ (begin
+ (close start-out)
+ ;; Wait for container to be ready.
+ (read start-in)
+ (close start-in)
+ (container-excursion pid
+ (lambda ()
+ ;; Fork again so that the pid is within the context of
+ ;; the joined pid namespace instead of the original pid
+ ;; namespace.
+ (match (primitive-fork)
+ (0
+ ;; Check that all of the namespace identifiers are
+ ;; the same as the container process.
+ (assert-exit
+ (equal? container-namespaces
+ (namespaces (getpid)))))
+ (fork-pid
+ (match (waitpid fork-pid)
+ ((_ . status)
+ (primitive-exit
+ (status:exit-val status)))))))))))
+ (close end-in)
+ ;; Stop the container.
+ (write 'done end-out)
+ (close end-out)
+ (waitpid pid)
+ (zero? result)))))))
+
+(test-end)
+
+
+(exit (= (test-runner-fail-count (test-runner-current)) 0))