environment: Add --link-profile.

This change is motivated by attempts to run programs (like GNU IceCat) within
containers.  The 'fontconfig' program, for example, is configured explicitly
to check ~/.guix-profile for additional fonts.

There were no existing container tests in 'tests/guix-environment.sh', but I
added one anyway for this change.

* doc/guix.texi (Invoking guix environment): Add '--link-profile'.
* guix/scripts/environment.scm (show-help): Add '--link-profile'.
(%options): Add 'link-profile' as '#\P', assigned to 'link-profile?'.
(link-environment): New procedure.
(launch-environment/container): Use it when 'link-profile?'.
[link-profile?]: New parameter.
(guix-environment): Leave when '--link-prof' but not '--container'.  Add
'#:link-profile?' argument to 'launch-environment/container' application.
* tests/guix-environment-container.sh: New '--link-profile' test.

Signed-off-by: Ludovic Courtès <ludo@gnu.org>
master
Mike Gerwitz 2018-01-25 22:29:15 -05:00 committed by Ludovic Courtès
parent 99654a1685
commit 07ec349229
No known key found for this signature in database
GPG Key ID: 090B11993D9AEBB5
3 changed files with 70 additions and 8 deletions

View File

@ -46,7 +46,8 @@ Copyright @copyright{} 2017 Andy Wingo@*
Copyright @copyright{} 2017, 2018 Arun Isaac@* Copyright @copyright{} 2017, 2018 Arun Isaac@*
Copyright @copyright{} 2017 nee@* Copyright @copyright{} 2017 nee@*
Copyright @copyright{} 2018 Rutger Helling@* Copyright @copyright{} 2018 Rutger Helling@*
Copyright @copyright{} 2018 Oleg Pykhalov Copyright @copyright{} 2018 Oleg Pykhalov@*
Copyright @copyright{} 2018 Mike Gerwitz
Permission is granted to copy, distribute and/or modify this document Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or under the terms of the GNU Free Documentation License, Version 1.3 or
@ -1572,7 +1573,7 @@ To be able to use such full names for the TrueType fonts installed in
your Guix profile, you need to extend the font path of the X server: your Guix profile, you need to extend the font path of the X server:
@example @example
xset +fp ~/.guix-profile/share/fonts/truetype xset +fp `readlink -f ~/.guix-profile/share/fonts/truetype`
@end example @end example
@cindex @code{xlsfonts} @cindex @code{xlsfonts}
@ -7296,6 +7297,22 @@ For containers, share the network namespace with the host system.
Containers created without this flag only have access to the loopback Containers created without this flag only have access to the loopback
device. device.
@item --link-profile
@itemx -P
For containers, link the environment profile to
@file{~/.guix-profile} within the container. This is equivalent to
running the command @command{ln -s $GUIX_ENVIRONMENT ~/.guix-profile}
within the container. Linking will fail and abort the environment if
the directory already exists, which will certainly be the case if
@command{guix environment} was invoked in the user's home directory.
Certain packages are configured to look in
@code{~/.guix-profile} for configuration files and data;@footnote{For
example, the @code{fontconfig} package inspects
@file{~/.guix-profile/share/fonts} for additional fonts.}
@code{--link-profile} allows these programs to behave as expected within
the environment.
@item --expose=@var{source}[=@var{target}] @item --expose=@var{source}[=@var{target}]
For containers, expose the file system @var{source} from the host system For containers, expose the file system @var{source} from the host system
as the read-only file system @var{target} within the container. If as the read-only file system @var{target} within the container. If

View File

@ -1,6 +1,7 @@
;;; GNU Guix --- Functional package management for GNU ;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2014, 2015, 2018 David Thompson <davet@gnu.org> ;;; Copyright © 2014, 2015, 2018 David Thompson <davet@gnu.org>
;;; Copyright © 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2018 Mike Gerwitz <mtg@gnu.org>
;;; ;;;
;;; This file is part of GNU Guix. ;;; This file is part of GNU Guix.
;;; ;;;
@ -159,6 +160,9 @@ COMMAND or an interactive shell in that environment.\n"))
-C, --container run command within an isolated container")) -C, --container run command within an isolated container"))
(display (G_ " (display (G_ "
-N, --network allow containers to access the network")) -N, --network allow containers to access the network"))
(display (G_ "
-P, --link-profile link environment profile to ~/.guix-profile within
an isolated container"))
(display (G_ " (display (G_ "
--share=SPEC for containers, share writable host file system --share=SPEC for containers, share writable host file system
according to SPEC")) according to SPEC"))
@ -243,6 +247,9 @@ COMMAND or an interactive shell in that environment.\n"))
(option '(#\N "network") #f #f (option '(#\N "network") #f #f
(lambda (opt name arg result) (lambda (opt name arg result)
(alist-cons 'network? #t result))) (alist-cons 'network? #t result)))
(option '(#\P "link-profile") #f #f
(lambda (opt name arg result)
(alist-cons 'link-profile? #t result)))
(option '("share") #t #f (option '("share") #t #f
(lambda (opt name arg result) (lambda (opt name arg result)
(alist-cons 'file-system-mapping (alist-cons 'file-system-mapping
@ -404,18 +411,20 @@ environment variables are cleared before setting the new ones."
((_ . status) status))))) ((_ . status) status)))))
(define* (launch-environment/container #:key command bash user-mappings (define* (launch-environment/container #:key command bash user-mappings
profile paths network?) profile paths link-profile? network?)
"Run COMMAND within a container that features the software in PROFILE. "Run COMMAND within a container that features the software in PROFILE.
Environment variables are set according to PATHS, a list of native search Environment variables are set according to PATHS, a list of native search
paths. The global shell is BASH, a file name for a GNU Bash binary in the paths. The global shell is BASH, a file name for a GNU Bash binary in the
store. When NETWORK?, access to the host system network is permitted. store. When NETWORK?, access to the host system network is permitted.
USER-MAPPINGS, a list of file system mappings, contains the user-specified USER-MAPPINGS, a list of file system mappings, contains the user-specified
host file systems to mount inside the container." host file systems to mount inside the container. LINK-PROFILE? creates a
symbolic link from ~/.guix-profile to the environment profile."
(mlet %store-monad ((reqs (inputs->requisites (mlet %store-monad ((reqs (inputs->requisites
(list (direct-store-path bash) profile)))) (list (direct-store-path bash) profile))))
(return (return
(let* ((cwd (getcwd)) (let* ((cwd (getcwd))
(passwd (getpwuid (getuid))) (passwd (getpwuid (getuid)))
(home-dir (passwd:dir passwd))
;; Bind-mount all requisite store items, user-specified mappings, ;; Bind-mount all requisite store items, user-specified mappings,
;; /bin/sh, the current working directory, and possibly networking ;; /bin/sh, the current working directory, and possibly networking
;; configuration files within the container. ;; configuration files within the container.
@ -460,8 +469,13 @@ host file systems to mount inside the container."
;; Create a dummy home directory under the same name as on the ;; Create a dummy home directory under the same name as on the
;; host. ;; host.
(mkdir-p (passwd:dir passwd)) (mkdir-p home-dir)
(setenv "HOME" (passwd:dir passwd)) (setenv "HOME" home-dir)
;; If requested, link $GUIX_ENVIRONMENT to $HOME/.guix-profile;
;; this allows programs expecting that path to continue working as
;; expected within a container.
(when link-profile? (link-environment profile home-dir))
;; Create a dummy /etc/passwd to satisfy applications that demand ;; Create a dummy /etc/passwd to satisfy applications that demand
;; to read it, such as 'git clone' over SSH, a valid use-case when ;; to read it, such as 'git clone' over SSH, a valid use-case when
@ -491,6 +505,18 @@ host file systems to mount inside the container."
(delq 'net %namespaces) ; share host network (delq 'net %namespaces) ; share host network
%namespaces))))))) %namespaces)))))))
(define (link-environment profile home-dir)
"Create a symbolic link from HOME-DIR/.guix-profile to PROFILE."
(let ((profile-dir (string-append home-dir "/.guix-profile")))
(catch 'system-error
(lambda ()
(symlink profile profile-dir))
(lambda args
(if (= EEXIST (system-error-errno args))
(leave (G_ "cannot link profile: '~a' already exists within container~%")
profile-dir)
(apply throw args))))))
(define (environment-bash container? bootstrap? system) (define (environment-bash container? bootstrap? system)
"Return a monadic value in the store monad for the version of GNU Bash "Return a monadic value in the store monad for the version of GNU Bash
needed in the environment for SYSTEM, if any. If CONTAINER? is #f, return #f. needed in the environment for SYSTEM, if any. If CONTAINER? is #f, return #f.
@ -564,6 +590,7 @@ message if any test fails."
(let* ((opts (parse-args args)) (let* ((opts (parse-args args))
(pure? (assoc-ref opts 'pure)) (pure? (assoc-ref opts 'pure))
(container? (assoc-ref opts 'container?)) (container? (assoc-ref opts 'container?))
(link-prof? (assoc-ref opts 'link-profile?))
(network? (assoc-ref opts 'network?)) (network? (assoc-ref opts 'network?))
(bootstrap? (assoc-ref opts 'bootstrap?)) (bootstrap? (assoc-ref opts 'bootstrap?))
(system (assoc-ref opts 'system)) (system (assoc-ref opts 'system))
@ -597,6 +624,9 @@ message if any test fails."
(when container? (assert-container-features)) (when container? (assert-container-features))
(when (and (not container?) link-prof?)
(leave (G_ "'--link-profile' cannot be used without '--container'~%")))
(with-store store (with-store store
(set-build-options-from-command-line store opts) (set-build-options-from-command-line store opts)
@ -646,6 +676,7 @@ message if any test fails."
#:user-mappings mappings #:user-mappings mappings
#:profile profile #:profile profile
#:paths paths #:paths paths
#:link-profile? link-prof?
#:network? network?))) #:network? network?)))
(else (else
(return (return

View File

@ -97,6 +97,20 @@ grep -e "$NIX_STORE_DIR/.*-bash" $tmpdir/mounts # bootstrap bash
rm $tmpdir/mounts rm $tmpdir/mounts
# Make sure 'GUIX_ENVIRONMENT' is linked to '~/.guix-profile' when requested
# within a container.
(
linktest='(exit (string=? (getenv "GUIX_ENVIRONMENT")
(readlink (string-append (getenv "HOME") "/.guix-profile"))))'
cd "$tmpdir" \
&& guix environment --bootstrap --container --link-profile \
--ad-hoc guile-bootstrap --pure \
-- guile -c "$linktest"
)
# Check the exit code.
abnormal_exit_code=" abnormal_exit_code="
(use-modules (system foreign)) (use-modules (system foreign))
;; Purposely make Guile crash with a segfault. :) ;; Purposely make Guile crash with a segfault. :)