mirror of
https://git.savannah.gnu.org/git/guix.git
synced 2025-01-18 21:46:35 +01:00
services: Add rootless-podman-service-type.
* gnu/services/containers.scm: New file; (rootless-podman-configuration): new variable; (rootless-podman-service-subids): new variable; (rootless-podman-service-accounts): new variable; (rootless-podman-service-profile): new variable; (rootless-podman-shepherd-services): new variable; (rootless-podman-service-etc): new variable; (rootless-podman-service-type): new variable. * gnu/local.mk: Test it. * gnu/local.mk: Add them. * doc/guix.texi (Miscellaneous Services): Document it. Change-Id: I041496474c1027da353bd6852f2554a065914d7a Signed-off-by: Ludovic Courtès <ludo@gnu.org>
This commit is contained in:
parent
17e5ca8190
commit
2767b4ef03
4 changed files with 690 additions and 0 deletions
110
doc/guix.texi
110
doc/guix.texi
|
@ -41292,6 +41292,116 @@ setuid-root (@pxref{Privileged Programs}) such that unprivileged users can
|
|||
invoke @command{singularity run} and similar commands.
|
||||
@end defvar
|
||||
|
||||
@cindex Rootless Podman
|
||||
@subsubheading Rootless Podman Service
|
||||
|
||||
@cindex rootless podman, container management tool
|
||||
@cindex podman, rootless
|
||||
@cindex container management, podman
|
||||
The @code{(gnu services containers)} module provides the following service.
|
||||
|
||||
|
||||
@defvar rootless-podman-service-type
|
||||
This is the service type for @url{https://podman.io, Podman} is a
|
||||
container management tool.
|
||||
|
||||
In addition to providing a drop-in replacement for Docker, Podman offers
|
||||
the ability to run containers in ``root-less'' mode, meaning that regular users can
|
||||
deploy containers without elevated privileges. It does so mainly by leveraging
|
||||
two Linux kernel features: unprivileged user namespaces, and subordinate
|
||||
user and group IDs (@pxref{subordinate-user-group-ids, the subordinate
|
||||
user and group ID service}).
|
||||
|
||||
The @code{rootless-podman-service-type} sets up the system to allow
|
||||
unprivileged users to run @command{podman} commands:
|
||||
|
||||
@lisp
|
||||
(use-service-modules containers networking @dots{})
|
||||
|
||||
(operating-system
|
||||
;; @dots{}
|
||||
(users (cons (user-account
|
||||
(name "alice")
|
||||
(comment "Bob's sister")
|
||||
(group "users")
|
||||
|
||||
;; Adding the account to the "cgroup" group
|
||||
;; makes it possible to run podman commands.
|
||||
(supplementary-groups '("cgroup" "wheel"
|
||||
"audio" "video")))
|
||||
%base-user-accounts))
|
||||
(services
|
||||
(append (list (service iptables-service-type)
|
||||
(service rootless-podman-service-type
|
||||
(rootless-podman-configuration
|
||||
(subgids
|
||||
(list (subid-range (name "alice"))))
|
||||
(subuids
|
||||
(list (subid-range (name "alice")))))))
|
||||
%base-services)))
|
||||
@end lisp
|
||||
|
||||
The @code{iptables-service-type} is required for Podman to be able to setup its
|
||||
own networks. Due to the change in user groups and file systems it is
|
||||
recommended to reboot (or at least logout), before trying to run Podman commands.
|
||||
|
||||
To test your installation you can run:
|
||||
|
||||
@example
|
||||
$ podman run -it --rm docker.io/alpine cat /etc/*release*
|
||||
NAME="Alpine Linux"
|
||||
ID=alpine
|
||||
VERSION_ID=3.20.2
|
||||
PRETTY_NAME="Alpine Linux v3.20"
|
||||
HOME_URL="https://alpinelinux.org/"
|
||||
BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"
|
||||
@end example
|
||||
|
||||
@end defvar
|
||||
|
||||
@c %start of fragment
|
||||
|
||||
@deftp {Data Type} rootless-podman-configuration
|
||||
Available @code{rootless-podman-configuration} fields are:
|
||||
|
||||
@table @asis
|
||||
@item @code{podman} (default: @code{podman}) (type: package)
|
||||
The Podman package that will be installed in the system profile.
|
||||
|
||||
@item @code{group-name} (default: @code{"cgroup"}) (type: string)
|
||||
The name of the group that will own /sys/fs/cgroup resources. Users that
|
||||
want to use rootless Podman have to be in this group.
|
||||
|
||||
@item @code{containers-registries} (type: lowerable)
|
||||
A string or a gexp evaluating to the path of Podman's
|
||||
@code{containers/registries.conf} configuration file.
|
||||
|
||||
@item @code{containers-storage} (type: lowerable)
|
||||
A string or a gexp evaluating to the path of Podman's
|
||||
@code{containers/storage.conf} configuration file.
|
||||
|
||||
@item @code{containers-policy} (type: lowerable)
|
||||
A string or a gexp evaluating to the path of Podman's
|
||||
@code{containers/policy.json} configuration file.
|
||||
|
||||
@item @code{pam-limits} (type: list-of-pam-limits-entries)
|
||||
The PAM limits to be set for rootless Podman.
|
||||
|
||||
@item @code{subgids} (default: @code{()}) (type: list-of-subid-ranges)
|
||||
A list of subid ranges representing the subgids that will be
|
||||
available for each configured user.
|
||||
|
||||
@item @code{subuids} (default: @code{()}) (type: list-of-subid-ranges)
|
||||
A list of subid ranges representing the subuids that will be
|
||||
available for each configured user.
|
||||
|
||||
@end table
|
||||
|
||||
@end deftp
|
||||
|
||||
|
||||
@c %end of fragment
|
||||
|
||||
@cindex OCI-backed, Shepherd services
|
||||
@subsubheading OCI backed services
|
||||
|
||||
|
|
|
@ -719,6 +719,7 @@ GNU_SYSTEM_MODULES = \
|
|||
%D%/services/cgit.scm \
|
||||
%D%/services/ci.scm \
|
||||
%D%/services/configuration.scm \
|
||||
%D%/services/containers.scm \
|
||||
%D%/services/cuirass.scm \
|
||||
%D%/services/cups.scm \
|
||||
%D%/services/databases.scm \
|
||||
|
@ -825,6 +826,7 @@ GNU_SYSTEM_MODULES = \
|
|||
%D%/tests/base.scm \
|
||||
%D%/tests/cachefilesd.scm \
|
||||
%D%/tests/ci.scm \
|
||||
%D%/tests/containers.scm \
|
||||
%D%/tests/cups.scm \
|
||||
%D%/tests/databases.scm \
|
||||
%D%/tests/desktop.scm \
|
||||
|
|
238
gnu/services/containers.scm
Normal file
238
gnu/services/containers.scm
Normal file
|
@ -0,0 +1,238 @@
|
|||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2024 Giacomo Leidi <goodoldpaul@autistici.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 (gnu services containers)
|
||||
#:use-module (gnu packages containers)
|
||||
#:use-module (gnu packages file-systems)
|
||||
#:use-module (gnu services)
|
||||
#:use-module (gnu services base)
|
||||
#:use-module (gnu services configuration)
|
||||
#:use-module (gnu services shepherd)
|
||||
#:use-module (gnu system accounts)
|
||||
#:use-module (gnu system shadow)
|
||||
#:use-module (gnu system pam)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix packages)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:export (rootless-podman-configuration
|
||||
rootless-podman-configuration?
|
||||
rootless-podman-configuration-fields
|
||||
rootless-podman-configuration-podman
|
||||
rootless-podman-configuration-group-name
|
||||
rootless-podman-configuration-containers-registries
|
||||
rootless-podman-configuration-containers-storage
|
||||
rootless-podman-configuration-containers-policy
|
||||
rootless-podman-configuration-pam-limits
|
||||
rootless-podman-configuration-subgids
|
||||
rootless-podman-configuration-subuids
|
||||
|
||||
rootless-podman-service-subids
|
||||
rootless-podman-service-accounts
|
||||
rootless-podman-service-profile
|
||||
rootless-podman-shepherd-services
|
||||
rootless-podman-service-etc
|
||||
|
||||
rootless-podman-service-type))
|
||||
|
||||
(define (gexp-or-string? value)
|
||||
(or (gexp? value)
|
||||
(string? value)))
|
||||
|
||||
(define (lowerable? value)
|
||||
(or (file-like? value)
|
||||
(gexp-or-string? value)))
|
||||
|
||||
(define list-of-pam-limits-entries?
|
||||
(list-of pam-limits-entry?))
|
||||
|
||||
(define list-of-subid-ranges?
|
||||
(list-of subid-range?))
|
||||
|
||||
(define-configuration/no-serialization rootless-podman-configuration
|
||||
(podman
|
||||
(package podman)
|
||||
"The Podman package that will be installed in the system profile.")
|
||||
(group-name
|
||||
(string "cgroup")
|
||||
"The name of the group that will own /sys/fs/cgroup resources. Users that
|
||||
want to use rootless Podman have to be in this group.")
|
||||
(containers-registries
|
||||
(lowerable
|
||||
(plain-file "registries.conf"
|
||||
(string-append "unqualified-search-registries = ['docker.io','"
|
||||
"registry.fedora.org','registry.opensuse.org']")))
|
||||
"A string or a gexp evaluating to the path of Podman's
|
||||
@code{containers/registries.conf} configuration file.")
|
||||
(containers-storage
|
||||
(lowerable
|
||||
(plain-file "storage.conf"
|
||||
"[storage]
|
||||
driver = \"overlay\""))
|
||||
"A string or a gexp evaluating to the path of Podman's
|
||||
@code{containers/storage.conf} configuration file.")
|
||||
(containers-policy
|
||||
(lowerable
|
||||
(plain-file "policy.json"
|
||||
"{\"default\": [{\"type\": \"insecureAcceptAnything\"}]}"))
|
||||
"A string or a gexp evaluating to the path of Podman's
|
||||
@code{containers/policy.json} configuration file.")
|
||||
(pam-limits
|
||||
(list-of-pam-limits-entries
|
||||
(list (pam-limits-entry "*" 'both 'nofile 100000)))
|
||||
"The PAM limits to be set for rootless Podman.")
|
||||
(subgids
|
||||
(list-of-subid-ranges '())
|
||||
"A list of subid ranges representing the subgids that will be
|
||||
available for each configured user.")
|
||||
(subuids
|
||||
(list-of-subid-ranges '())
|
||||
"A list of subid ranges representing the subuids that will be
|
||||
available for each configured user."))
|
||||
|
||||
(define rootless-podman-service-profile
|
||||
(lambda (config)
|
||||
(list
|
||||
(rootless-podman-configuration-podman config))))
|
||||
|
||||
(define rootless-podman-service-etc
|
||||
(lambda (config)
|
||||
(list `("containers/registries.conf"
|
||||
,(rootless-podman-configuration-containers-registries config))
|
||||
`("containers/storage.conf"
|
||||
,(rootless-podman-configuration-containers-storage config))
|
||||
`("containers/policy.json"
|
||||
,(rootless-podman-configuration-containers-policy config)))))
|
||||
|
||||
(define rootless-podman-service-subids
|
||||
(lambda (config)
|
||||
(subids-extension
|
||||
(subgids (rootless-podman-configuration-subgids config))
|
||||
(subuids (rootless-podman-configuration-subuids config)))))
|
||||
|
||||
(define rootless-podman-service-accounts
|
||||
(lambda (config)
|
||||
(list (user-group (name (rootless-podman-configuration-group-name config))
|
||||
(system? #t)))))
|
||||
|
||||
(define (cgroups-fs-owner-entrypoint config)
|
||||
(define group
|
||||
(rootless-podman-configuration-group-name config))
|
||||
(program-file "cgroups2-fs-owner-entrypoint"
|
||||
#~(system*
|
||||
"bash" "-c"
|
||||
(string-append "echo Setting /sys/fs/cgroup "
|
||||
"group ownership to " #$group " && chown -v "
|
||||
"root:" #$group " /sys/fs/cgroup && "
|
||||
"chmod -v 775 /sys/fs/cgroup && chown -v "
|
||||
"root:" #$group " /sys/fs/cgroup/cgroup."
|
||||
"{procs,subtree_control,threads} && "
|
||||
"chmod -v 664 /sys/fs/cgroup/cgroup."
|
||||
"{procs,subtree_control,threads}"))))
|
||||
|
||||
(define (rootless-podman-cgroups-fs-owner-service config)
|
||||
(shepherd-service (provision '(cgroups2-fs-owner))
|
||||
(requirement
|
||||
'(dbus-system
|
||||
elogind
|
||||
file-system-/sys/fs/cgroup
|
||||
networking
|
||||
udev
|
||||
cgroups2-limits))
|
||||
(one-shot? #t)
|
||||
(documentation
|
||||
"Set ownership of /sys/fs/cgroup to the configured group.")
|
||||
(start
|
||||
#~(make-forkexec-constructor
|
||||
(list
|
||||
#$(cgroups-fs-owner-entrypoint config))))
|
||||
(stop
|
||||
#~(make-kill-destructor))))
|
||||
|
||||
(define cgroups-limits-entrypoint
|
||||
(program-file "cgroups2-limits-entrypoint"
|
||||
#~(system*
|
||||
"bash" "-c"
|
||||
(string-append "echo Setting cgroups v2 limits && "
|
||||
"echo +cpu +cpuset +memory +pids"
|
||||
" >> /sys/fs/cgroup/cgroup.subtree_control"))))
|
||||
|
||||
(define (rootless-podman-cgroups-limits-service config)
|
||||
(shepherd-service (provision '(cgroups2-limits))
|
||||
(requirement
|
||||
'(dbus-system
|
||||
elogind
|
||||
networking
|
||||
udev
|
||||
file-system-/sys/fs/cgroup
|
||||
rootless-podman-shared-root-fs))
|
||||
(one-shot? #t)
|
||||
(documentation
|
||||
"Allow setting cgroups limits: cpu, cpuset, memory and
|
||||
pids.")
|
||||
(start
|
||||
#~(make-forkexec-constructor
|
||||
(list
|
||||
#$cgroups-limits-entrypoint)))
|
||||
(stop
|
||||
#~(make-kill-destructor))))
|
||||
|
||||
(define rootless-podman-shared-root-fs-entrypoint
|
||||
(program-file "rootless-podman-shared-root-fs-entrypoint"
|
||||
#~(system*
|
||||
"mount" "--make-shared" "/")))
|
||||
|
||||
(define (rootless-podman-shared-root-fs-service config)
|
||||
(shepherd-service (provision '(rootless-podman-shared-root-fs))
|
||||
(requirement
|
||||
'(user-processes))
|
||||
(one-shot? #t)
|
||||
(documentation
|
||||
"Buildah/Podman running as rootless expects the bind mount
|
||||
to be shared. This service sets it so.")
|
||||
(start
|
||||
#~(make-forkexec-constructor
|
||||
(list
|
||||
#$rootless-podman-shared-root-fs-entrypoint)))
|
||||
(stop
|
||||
#~(make-kill-destructor))))
|
||||
|
||||
(define (rootless-podman-shepherd-services config)
|
||||
(list
|
||||
(rootless-podman-shared-root-fs-service config)
|
||||
(rootless-podman-cgroups-limits-service config)
|
||||
(rootless-podman-cgroups-fs-owner-service config)))
|
||||
|
||||
(define rootless-podman-service-type
|
||||
(service-type (name 'rootless-podman)
|
||||
(extensions
|
||||
(list
|
||||
(service-extension subids-service-type
|
||||
rootless-podman-service-subids)
|
||||
(service-extension account-service-type
|
||||
rootless-podman-service-accounts)
|
||||
(service-extension profile-service-type
|
||||
rootless-podman-service-profile)
|
||||
(service-extension shepherd-root-service-type
|
||||
rootless-podman-shepherd-services)
|
||||
(service-extension pam-limits-service-type
|
||||
rootless-podman-configuration-pam-limits)
|
||||
(service-extension etc-service-type
|
||||
rootless-podman-service-etc)))
|
||||
(default-value (rootless-podman-configuration))
|
||||
(description
|
||||
"This service configures rootless @code{podman} on the Guix System.")))
|
340
gnu/tests/containers.scm
Normal file
340
gnu/tests/containers.scm
Normal file
|
@ -0,0 +1,340 @@
|
|||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2024 Giacomo Leidi <goodoldpaul@autistici.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 (gnu tests containers)
|
||||
#:use-module (gnu)
|
||||
#:use-module (gnu tests)
|
||||
#:use-module (guix build-system trivial)
|
||||
#:use-module (gnu packages bash)
|
||||
#:use-module (gnu packages containers)
|
||||
#:use-module (gnu packages guile)
|
||||
#:use-module (gnu packages guile-xyz)
|
||||
#:use-module (gnu services)
|
||||
#:use-module (gnu services containers)
|
||||
#:use-module (gnu services desktop)
|
||||
#:use-module (gnu services dbus)
|
||||
#:use-module (gnu services networking)
|
||||
#:use-module (gnu system)
|
||||
#:use-module (gnu system accounts)
|
||||
#:use-module (gnu system vm)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module ((guix licenses) #:prefix license:)
|
||||
#:use-module (guix monads)
|
||||
#:use-module (guix packages)
|
||||
#:use-module (guix profiles)
|
||||
#:use-module ((guix scripts pack) #:prefix pack:)
|
||||
#:use-module (guix store)
|
||||
#:export (%test-rootless-podman))
|
||||
|
||||
|
||||
(define %rootless-podman-os
|
||||
(simple-operating-system
|
||||
(service rootless-podman-service-type
|
||||
(rootless-podman-configuration
|
||||
(subgids
|
||||
(list (subid-range (name "dummy"))))
|
||||
(subuids
|
||||
(list (subid-range (name "dummy"))))))
|
||||
|
||||
(service dhcp-client-service-type)
|
||||
(service dbus-root-service-type)
|
||||
(service polkit-service-type)
|
||||
(service elogind-service-type)
|
||||
|
||||
(simple-service 'accounts
|
||||
account-service-type
|
||||
(list (user-account
|
||||
(name "dummy")
|
||||
(group "users")
|
||||
(supplementary-groups '("wheel" "netdev" "cgroup"
|
||||
"audio" "video")))))))
|
||||
|
||||
(define (run-rootless-podman-test oci-tarball)
|
||||
|
||||
(define os
|
||||
(marionette-operating-system
|
||||
(operating-system-with-gc-roots
|
||||
%rootless-podman-os
|
||||
(list oci-tarball))
|
||||
#:imported-modules '((gnu services herd)
|
||||
(guix combinators))))
|
||||
|
||||
(define vm
|
||||
(virtual-machine
|
||||
(operating-system os)
|
||||
(volatile? #f)
|
||||
(memory-size 1024)
|
||||
(disk-image-size (* 3000 (expt 2 20)))
|
||||
(port-forwardings '())))
|
||||
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette)
|
||||
(gnu services herd))
|
||||
#~(begin
|
||||
(use-modules (srfi srfi-11) (srfi srfi-64)
|
||||
(gnu build marionette))
|
||||
|
||||
(define marionette
|
||||
;; Relax timeout to accommodate older systems and
|
||||
;; allow for pulling the image.
|
||||
(make-marionette (list #$vm) #:timeout 60))
|
||||
(define out-dir "/tmp")
|
||||
|
||||
(test-runner-current (system-test-runner #$output))
|
||||
(test-begin "rootless-podman")
|
||||
|
||||
(test-assert "service started"
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd))
|
||||
(match (start-service 'cgroups2-fs-owner)
|
||||
(#f #f)
|
||||
;; herd returns (running #f), likely because of one shot,
|
||||
;; so consider any non-error a success.
|
||||
(('service response-parts ...) #t)))
|
||||
marionette))
|
||||
|
||||
(test-equal "/sys/fs/cgroup/cgroup.subtree_control content is sound"
|
||||
(list "cpu" "cpuset" "memory" "pids")
|
||||
(marionette-eval
|
||||
`(begin
|
||||
(use-modules (srfi srfi-1)
|
||||
(ice-9 popen)
|
||||
(ice-9 match)
|
||||
(ice-9 rdelim))
|
||||
|
||||
(define (read-lines file-or-port)
|
||||
(define (loop-lines port)
|
||||
(let loop ((lines '()))
|
||||
(match (read-line port)
|
||||
((? eof-object?)
|
||||
(reverse lines))
|
||||
(line
|
||||
(loop (cons line lines))))))
|
||||
|
||||
(if (port? file-or-port)
|
||||
(loop-lines file-or-port)
|
||||
(call-with-input-file file-or-port
|
||||
loop-lines)))
|
||||
|
||||
(define slurp
|
||||
(lambda args
|
||||
(let* ((port (apply open-pipe* OPEN_READ args))
|
||||
(output (read-lines port))
|
||||
(status (close-pipe port)))
|
||||
output)))
|
||||
(let* ((response1 (slurp
|
||||
,(string-append #$coreutils "/bin/cat")
|
||||
"/sys/fs/cgroup/cgroup.subtree_control")))
|
||||
(sort-list (string-split (first response1) #\space) string<?)))
|
||||
marionette))
|
||||
|
||||
(test-equal "/sys/fs/cgroup has correct permissions"
|
||||
'("cgroup" "cgroup")
|
||||
(marionette-eval
|
||||
`(begin
|
||||
(use-modules (ice-9 popen)
|
||||
(ice-9 match)
|
||||
(ice-9 rdelim))
|
||||
|
||||
(define (read-lines file-or-port)
|
||||
(define (loop-lines port)
|
||||
(let loop ((lines '()))
|
||||
(match (read-line port)
|
||||
((? eof-object?)
|
||||
(reverse lines))
|
||||
(line
|
||||
(loop (cons line lines))))))
|
||||
|
||||
(if (port? file-or-port)
|
||||
(loop-lines file-or-port)
|
||||
(call-with-input-file file-or-port
|
||||
loop-lines)))
|
||||
|
||||
(define slurp
|
||||
(lambda args
|
||||
(let* ((port (apply open-pipe* OPEN_READ args))
|
||||
(output (read-lines port))
|
||||
(status (close-pipe port)))
|
||||
output)))
|
||||
(let* ((bash
|
||||
,(string-append #$bash "/bin/bash"))
|
||||
(response1
|
||||
(slurp bash "-c"
|
||||
(string-append "ls -la /sys/fs/cgroup | "
|
||||
"grep -E ' \\./?$' | awk '{ print $4 }'")))
|
||||
(response2 (slurp bash "-c"
|
||||
(string-append "ls -l /sys/fs/cgroup/cgroup"
|
||||
".{procs,subtree_control,threads} | "
|
||||
"awk '{ print $4 }' | sort -u"))))
|
||||
(list (string-join response1 "\n") (string-join response2 "\n"))))
|
||||
marionette))
|
||||
|
||||
(test-equal "Load oci image and run it (unprivileged)"
|
||||
'("hello world" "hi!" "JSON!" #o1777)
|
||||
(marionette-eval
|
||||
`(begin
|
||||
(use-modules (srfi srfi-1)
|
||||
(ice-9 popen)
|
||||
(ice-9 match)
|
||||
(ice-9 rdelim))
|
||||
|
||||
(define (wait-for-file file)
|
||||
;; Wait until FILE shows up.
|
||||
(let loop ((i 60))
|
||||
(cond ((file-exists? file)
|
||||
#t)
|
||||
((zero? i)
|
||||
(error "file didn't show up" file))
|
||||
(else
|
||||
(pk 'wait-for-file file)
|
||||
(sleep 1)
|
||||
(loop (- i 1))))))
|
||||
|
||||
(define (read-lines file-or-port)
|
||||
(define (loop-lines port)
|
||||
(let loop ((lines '()))
|
||||
(match (read-line port)
|
||||
((? eof-object?)
|
||||
(reverse lines))
|
||||
(line
|
||||
(loop (cons line lines))))))
|
||||
|
||||
(if (port? file-or-port)
|
||||
(loop-lines file-or-port)
|
||||
(call-with-input-file file-or-port
|
||||
loop-lines)))
|
||||
|
||||
(define slurp
|
||||
(lambda args
|
||||
(let* ((port (apply open-pipe* OPEN_READ
|
||||
(list "sh" "-l" "-c"
|
||||
(string-join
|
||||
args
|
||||
" "))))
|
||||
(output (read-lines port))
|
||||
(status (close-pipe port)))
|
||||
output)))
|
||||
|
||||
(match (primitive-fork)
|
||||
(0
|
||||
(dynamic-wind
|
||||
(const #f)
|
||||
(lambda ()
|
||||
(setgid (passwd:gid (getpwnam "dummy")))
|
||||
(setuid (passwd:uid (getpw "dummy")))
|
||||
|
||||
(let* ((loaded (slurp ,(string-append #$podman
|
||||
"/bin/podman")
|
||||
"load" "-i"
|
||||
,#$oci-tarball))
|
||||
(repository&tag "localhost/guile-guest:latest")
|
||||
(response1 (slurp
|
||||
,(string-append #$podman "/bin/podman")
|
||||
"run" "--pull" "never"
|
||||
"--entrypoint" "bin/Guile"
|
||||
repository&tag
|
||||
"/aa.scm"))
|
||||
(response2 (slurp ;default entry point
|
||||
,(string-append #$podman "/bin/podman")
|
||||
"run" "--pull" "never" repository&tag
|
||||
"-c" "'(display \"hi!\")'"))
|
||||
|
||||
;; Check whether (json) is in $GUILE_LOAD_PATH.
|
||||
(response3 (slurp ;default entry point + environment
|
||||
,(string-append #$podman "/bin/podman")
|
||||
"run" "--pull" "never" repository&tag
|
||||
"-c" "'(use-modules (json))
|
||||
(display (json-string->scm (scm->json-string \"JSON!\")))'"))
|
||||
|
||||
;; Check whether /tmp exists.
|
||||
(response4 (slurp
|
||||
,(string-append #$podman "/bin/podman")
|
||||
"run" "--pull" "never" repository&tag "-c"
|
||||
"'(display (stat:perms (lstat \"/tmp\")))'")))
|
||||
(call-with-output-file (string-append ,out-dir "/response1")
|
||||
(lambda (port)
|
||||
(display (string-join response1 " ") port)))
|
||||
(call-with-output-file (string-append ,out-dir "/response2")
|
||||
(lambda (port)
|
||||
(display (string-join response2 " ") port)))
|
||||
(call-with-output-file (string-append ,out-dir "/response3")
|
||||
(lambda (port)
|
||||
(display (string-join response3 " ") port)))
|
||||
(call-with-output-file (string-append ,out-dir "/response4")
|
||||
(lambda (port)
|
||||
(display (string-join response4 " ") port)))))
|
||||
(lambda ()
|
||||
(primitive-exit 127))))
|
||||
(pid
|
||||
(cdr (waitpid pid))))
|
||||
(wait-for-file (string-append ,out-dir "/response4"))
|
||||
(append
|
||||
(slurp "cat" (string-append ,out-dir "/response1"))
|
||||
(slurp "cat" (string-append ,out-dir "/response2"))
|
||||
(slurp "cat" (string-append ,out-dir "/response3"))
|
||||
(map string->number (slurp "cat" (string-append ,out-dir "/response4")))))
|
||||
marionette))
|
||||
|
||||
(test-end))))
|
||||
|
||||
(gexp->derivation "rootless-podman-test" test))
|
||||
|
||||
(define (build-tarball&run-rootless-podman-test)
|
||||
(mlet* %store-monad
|
||||
((_ (set-grafting #f))
|
||||
(guile (set-guile-for-build (default-guile)))
|
||||
(guest-script-package ->
|
||||
(package
|
||||
(name "guest-script")
|
||||
(version "0")
|
||||
(source #f)
|
||||
(build-system trivial-build-system)
|
||||
(arguments `(#:guile ,guile-3.0
|
||||
#:builder
|
||||
(let ((out (assoc-ref %outputs "out")))
|
||||
(mkdir out)
|
||||
(call-with-output-file (string-append out "/a.scm")
|
||||
(lambda (port)
|
||||
(display "(display \"hello world\n\")" port)))
|
||||
#t)))
|
||||
(synopsis "Display hello world using Guile")
|
||||
(description "This package displays the text \"hello world\" on the
|
||||
standard output device and then enters a new line.")
|
||||
(home-page #f)
|
||||
(license license:public-domain)))
|
||||
(profile (profile-derivation (packages->manifest
|
||||
(list guile-3.0 guile-json-3
|
||||
guest-script-package))
|
||||
#:hooks '()
|
||||
#:locales? #f))
|
||||
(tarball (pack:docker-image
|
||||
"docker-pack" profile
|
||||
#:symlinks '(("/bin/Guile" -> "bin/guile")
|
||||
("aa.scm" -> "a.scm"))
|
||||
#:extra-options
|
||||
'(#:image-tag "guile-guest")
|
||||
#:entry-point "bin/guile"
|
||||
#:localstatedir? #t)))
|
||||
(run-rootless-podman-test tarball)))
|
||||
|
||||
(define %test-rootless-podman
|
||||
(system-test
|
||||
(name "rootless-podman")
|
||||
(description "Test rootless Podman service.")
|
||||
(value (build-tarball&run-rootless-podman-test))))
|
Loading…
Reference in a new issue