aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.packit.sh27
-rw-r--r--.packit.yaml20
-rw-r--r--Makefile3
-rw-r--r--cmd/podman/machine/init.go5
-rw-r--r--docs/source/markdown/.gitignore1
-rw-r--r--docs/source/markdown/options/restart.md15
-rw-r--r--docs/source/markdown/options/signal.md4
-rw-r--r--docs/source/markdown/options/userns.container.md47
-rw-r--r--docs/source/markdown/podman-create.1.md.in59
-rw-r--r--docs/source/markdown/podman-kill.1.md.in5
-rw-r--r--docs/source/markdown/podman-kube-play.1.md.in42
-rw-r--r--docs/source/markdown/podman-machine-init.1.md6
-rw-r--r--docs/source/markdown/podman-pod-kill.1.md.in (renamed from docs/source/markdown/podman-pod-kill.1.md)5
-rw-r--r--docs/source/markdown/podman-run.1.md.in60
-rw-r--r--go.mod2
-rw-r--r--go.sum4
-rw-r--r--libpod/container.go3
-rw-r--r--libpod/container_internal.go9
-rw-r--r--libpod/oci_conmon_freebsd.go5
-rw-r--r--libpod/options.go7
-rw-r--r--libpod/runtime_ctr.go11
-rw-r--r--pkg/bindings/images/images.go4
-rw-r--r--pkg/bindings/images/pull.go4
-rw-r--r--pkg/bindings/images/push.go5
-rw-r--r--pkg/bindings/images/types.go10
-rw-r--r--pkg/bindings/internal/util/util.go3
-rw-r--r--pkg/bindings/kube/kube.go4
-rw-r--r--pkg/bindings/kube/types.go2
-rw-r--r--pkg/bindings/manifests/manifests.go10
-rw-r--r--pkg/bindings/manifests/types.go4
-rw-r--r--pkg/bindings/test/types_test.go66
-rw-r--r--pkg/domain/infra/abi/play.go2
-rw-r--r--pkg/domain/infra/runtime_libpod.go51
-rw-r--r--pkg/k8s.io/api/core/v1/types.go4
-rw-r--r--pkg/machine/e2e/config_init_test.go10
-rw-r--r--pkg/machine/e2e/init_test.go20
-rw-r--r--pkg/namespaces/namespaces.go49
-rw-r--r--pkg/specgen/generate/config_unsupported.go29
-rw-r--r--pkg/specgen/generate/container_create.go7
-rw-r--r--pkg/specgen/generate/kube/kube.go9
-rw-r--r--pkg/specgen/generate/kube/volume.go14
-rw-r--r--pkg/specgen/generate/namespaces.go160
-rw-r--r--pkg/specgen/generate/namespaces_freebsd.go51
-rw-r--r--pkg/specgen/generate/namespaces_linux.go160
-rw-r--r--pkg/specgen/generate/namespaces_unsupported.go16
-rw-r--r--pkg/specgen/generate/oci.go317
-rw-r--r--pkg/specgen/generate/oci_freebsd.go96
-rw-r--r--pkg/specgen/generate/oci_linux.go331
-rw-r--r--pkg/specgen/generate/oci_unsupported.go24
-rw-r--r--pkg/specgen/generate/security_freebsd.go19
-rw-r--r--pkg/specgen/generate/security_linux.go (renamed from pkg/specgen/generate/security.go)0
-rw-r--r--pkg/specgen/generate/security_unsupported.go24
-rw-r--r--pkg/specgen/namespaces.go15
-rw-r--r--pkg/specgen/volumes.go3
-rw-r--r--pkg/util/utils.go8
-rw-r--r--test/e2e/play_kube_test.go51
-rw-r--r--test/e2e/run_userns_test.go10
-rw-r--r--test/system/090-events.bats5
-rw-r--r--vendor/github.com/containers/common/libimage/image.go4
-rw-r--r--vendor/modules.txt2
60 files changed, 1137 insertions, 806 deletions
diff --git a/.packit.sh b/.packit.sh
deleted file mode 100644
index 7b404598a..000000000
--- a/.packit.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env bash
-
-# Packit's default fix-spec-file often doesn't fetch version string correctly.
-# This script handles any custom processing of the dist-git spec file and gets used by the
-# fix-spec-file action in .packit.yaml
-
-set -eo pipefail
-
-# Get Version from HEAD
-HEAD_VERSION=$(grep 'var Version = semver.MustParse' version/version.go | cut -d\" -f2 | sed -e 's/-/~/')
-
-# Generate source tarball
-git archive --prefix=podman-$HEAD_VERSION/ -o podman-$HEAD_VERSION.tar.gz HEAD
-
-# RPM Spec modifications
-
-# Fix Version
-sed -i "s/^Version:.*/Version: $HEAD_VERSION/" podman.spec
-
-# Fix Release
-sed -i "s/^Release: %autorelease/Release: $PACKIT_RPMSPEC_RELEASE%{?dist}/" podman.spec
-
-# Fix Source0
-sed -i "s/^Source0:.*.tar.gz/Source0: %{name}-$HEAD_VERSION.tar.gz/" podman.spec
-
-# Fix autosetup
-sed -i "s/^%autosetup.*/%autosetup -Sgit -n %{name}-$HEAD_VERSION/" podman.spec
diff --git a/.packit.yaml b/.packit.yaml
deleted file mode 100644
index ab284b2d5..000000000
--- a/.packit.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-# See the documentation for more information:
-# https://packit.dev/docs/configuration/
-
-upstream_package_name: podman
-downstream_package_name: podman
-
-actions:
- post-upstream-clone:
- - "curl -O https://src.fedoraproject.org/rpms/podman/raw/main/f/podman.spec"
- fix-spec-file:
- - bash .packit.sh
-
-jobs:
- - job: production_build
- trigger: pull_request
- targets: &production_dist_targets
- - fedora-36
- - fedora-37
- - fedora-rawhide
- scratch: true
diff --git a/Makefile b/Makefile
index d10c9cf19..0ced638a6 100644
--- a/Makefile
+++ b/Makefile
@@ -285,8 +285,9 @@ vendor:
.PHONY: vendor-in-container
vendor-in-container:
- podman run --privileged --rm --env HOME=/root \
+ podman run --rm --env HOME=/root \
-v $(CURDIR):/src -w /src \
+ --security-opt label=disable \
docker.io/library/golang:1.17 \
make vendor
diff --git a/cmd/podman/machine/init.go b/cmd/podman/machine/init.go
index def3334e8..0848147a8 100644
--- a/cmd/podman/machine/init.go
+++ b/cmd/podman/machine/init.go
@@ -42,7 +42,6 @@ func init() {
})
flags := initCmd.Flags()
cfg := registry.PodmanConfig()
- initOpts.Username = cfg.Config.Machine.User
cpusFlagName := "cpus"
flags.Uint64Var(
@@ -89,6 +88,10 @@ func init() {
)
_ = flags.MarkHidden("reexec")
+ UsernameFlagName := "username"
+ flags.StringVar(&initOpts.Username, UsernameFlagName, cfg.Machine.User, "Username used in qcow image")
+ _ = initCmd.RegisterFlagCompletionFunc(UsernameFlagName, completion.AutocompleteDefault)
+
ImagePathFlagName := "image-path"
flags.StringVar(&initOpts.ImagePath, ImagePathFlagName, cfg.Machine.Image, "Path to qcow image")
_ = initCmd.RegisterFlagCompletionFunc(ImagePathFlagName, completion.AutocompleteDefault)
diff --git a/docs/source/markdown/.gitignore b/docs/source/markdown/.gitignore
index 8a0d553ba..26509612d 100644
--- a/docs/source/markdown/.gitignore
+++ b/docs/source/markdown/.gitignore
@@ -15,6 +15,7 @@ podman-manifest-push.1.md
podman-pause.1.md
podman-pod-clone.1.md
podman-pod-create.1.md
+podman-pod-kill.1.md
podman-pod-logs.1.md
podman-pod-rm.1.md
podman-pod-start.1.md
diff --git a/docs/source/markdown/options/restart.md b/docs/source/markdown/options/restart.md
new file mode 100644
index 000000000..825ae613f
--- /dev/null
+++ b/docs/source/markdown/options/restart.md
@@ -0,0 +1,15 @@
+#### **--restart**=*policy*
+
+Restart policy to follow when containers exit.
+Restart policy will not take effect if a container is stopped via the **podman kill** or **podman stop** commands.
+
+Valid _policy_ values are:
+
+- `no` : Do not restart containers on exit
+- `on-failure[:max_retries]` : Restart containers when they exit with a non-zero exit code, retrying indefinitely or until the optional *max_retries* count is hit
+- `always` : Restart containers when they exit, regardless of status, retrying indefinitely
+- `unless-stopped` : Identical to **always**
+
+Please note that restart will not restart containers after a system reboot.
+If this functionality is required in your environment, you can invoke Podman from a **systemd.unit**(5) file, or create an init script for whichever init system is in use.
+To generate systemd unit files, please see **podman generate systemd**.
diff --git a/docs/source/markdown/options/signal.md b/docs/source/markdown/options/signal.md
new file mode 100644
index 000000000..6e6c03657
--- /dev/null
+++ b/docs/source/markdown/options/signal.md
@@ -0,0 +1,4 @@
+#### **--signal**, **-s**=**signal**
+
+Signal to send to the container<<|s in the pod>>. For more information on Linux signals, refer to *signal(7)*.
+The default is **SIGKILL**.
diff --git a/docs/source/markdown/options/userns.container.md b/docs/source/markdown/options/userns.container.md
new file mode 100644
index 000000000..8f96892df
--- /dev/null
+++ b/docs/source/markdown/options/userns.container.md
@@ -0,0 +1,47 @@
+#### **--userns**=*mode*
+
+Set the user namespace mode for the container. It defaults to the **PODMAN_USERNS** environment variable. An empty value ("") means user namespaces are disabled unless an explicit mapping is set with the **--uidmap** and **--gidmap** options.
+
+This option is incompatible with **--gidmap**, **--uidmap**, **--subuidname** and **--subgidname**.
+
+Rootless user --userns=Key mappings:
+
+Key | Host User | Container User
+----------|---------------|---------------------
+"" |$UID |0 (Default User account mapped to root user in container.)
+keep-id |$UID |$UID (Map user account to same UID within container.)
+auto |$UID | nil (Host User UID is not mapped into container.)
+nomap |$UID | nil (Host User UID is not mapped into container.)
+
+Valid _mode_ values are:
+
+**auto**[:_OPTIONS,..._]: automatically create a unique user namespace.
+
+The `--userns=auto` flag, requires that the user name `containers` and a range of subordinate user ids that the Podman container is allowed to use be specified in the /etc/subuid and /etc/subgid files.
+
+Example: `containers:2147483647:2147483648`.
+
+Podman allocates unique ranges of UIDs and GIDs from the `containers` subordinate user ids. The size of the ranges is based on the number of UIDs required in the image. The number of UIDs and GIDs can be overridden with the `size` option.
+
+The rootless option `--userns=keep-id` uses all the subuids and subgids of the user. Using `--userns=auto` when starting new containers will not work as long as any containers exist that were started with `--userns=keep-id`.
+
+ Valid `auto` options:
+
+ - *gidmapping*=_CONTAINER_GID:HOST_GID:SIZE_: to force a GID mapping to be present in the user namespace.
+ - *size*=_SIZE_: to specify an explicit size for the automatic user namespace. e.g. `--userns=auto:size=8192`. If `size` is not specified, `auto` will estimate a size for the user namespace.
+ - *uidmapping*=_CONTAINER_UID:HOST_UID:SIZE_: to force a UID mapping to be present in the user namespace.
+
+**container:**_id_: join the user namespace of the specified container.
+
+**host**: run in the user namespace of the caller. The processes running in the container will have the same privileges on the host as any other process launched by the calling user (default).
+
+**keep-id**: creates a user namespace where the current rootless user's UID:GID are mapped to the same values in the container. This option is not allowed for containers created by the root user.
+
+ Valid `keep-id` options:
+
+ - *uid*=UID: override the UID inside the container that will be used to map the current rootless user to.
+ - *gid*=GID: override the GID inside the container that will be used to map the current rootless user to.
+
+**nomap**: creates a user namespace where the current rootless user's UID:GID are not mapped into the container. This option is not allowed for containers created by the root user.
+
+**ns:**_namespace_: run the <<container|pod>> in the given existing user namespace.
diff --git a/docs/source/markdown/podman-create.1.md.in b/docs/source/markdown/podman-create.1.md.in
index 00c374992..2fad2deb1 100644
--- a/docs/source/markdown/podman-create.1.md.in
+++ b/docs/source/markdown/podman-create.1.md.in
@@ -500,21 +500,7 @@ Suppress output information when pulling images
@@option requires
-#### **--restart**=*policy*
-
-Restart policy to follow when containers exit.
-Restart policy will not take effect if a container is stopped via the `podman kill` or `podman stop` commands.
-
-Valid values are:
-
-- `no` : Do not restart containers on exit
-- `on-failure[:max_retries]` : Restart containers when they exit with a non-0 exit code, retrying indefinitely or until the optional max_retries count is hit
-- `always` : Restart containers when they exit, regardless of status, retrying indefinitely
-- `unless-stopped` : Identical to **always**
-
-Please note that restart will not restart containers after a system reboot.
-If this functionality is required in your environment, you can invoke Podman from a systemd unit file, or create an init script for whichever init system is in use.
-To generate systemd unit files, please see *podman generate systemd*
+@@option restart
#### **--rm**
@@ -648,48 +634,7 @@ The following examples are all valid:
Without this argument the command will be run as root in the container.
-#### **--userns**=*mode*
-
-Set the user namespace mode for the container. It defaults to the **PODMAN_USERNS** environment variable. An empty value ("") means user namespaces are disabled unless an explicit mapping is set with the **--uidmap** and **--gidmap** options.
-
-Rootless user --userns=Key mappings:
-
-Key | Host User | Container User
-----------|---------------|---------------------
-"" |$UID |0 (Default User account mapped to root user in container.)
-keep-id |$UID |$UID (Map user account to same UID within container.)
-auto |$UID | nil (Host User UID is not mapped into container.)
-nomap |$UID | nil (Host User UID is not mapped into container.)
-
-Valid _mode_ values are:
-
-**auto**[:_OPTIONS,..._]: automatically create a unique user namespace.
-
-The `--userns=auto` flag, requires that the user name `containers` and a range of subordinate user ids that the Podman container is allowed to use be specified in the /etc/subuid and /etc/subgid files.
-
-Example: `containers:2147483647:2147483648`.
-
-Podman allocates unique ranges of UIDs and GIDs from the `containers` subordinate user ids. The size of the ranges is based on the number of UIDs required in the image. The number of UIDs and GIDs can be overridden with the `size` option. The `auto` options currently does not work in rootless mode
-
- Valid `auto` options:
-
- - *gidmapping*=_CONTAINER_GID:HOST_GID:SIZE_: to force a GID mapping to be present in the user namespace.
- - *size*=_SIZE_: to specify an explicit size for the automatic user namespace. e.g. `--userns=auto:size=8192`. If `size` is not specified, `auto` will estimate a size for the user namespace.
- - *uidmapping*=_CONTAINER_UID:HOST_UID:SIZE_: to force a UID mapping to be present in the user namespace.
-
-**container:**_id_: join the user namespace of the specified container.
-
-**host**: run in the user namespace of the caller. The processes running in the container will have the same privileges on the host as any other process launched by the calling user (default).
-
-**keep-id**: creates a user namespace where the current rootless user's UID:GID are mapped to the same values in the container. This option is not allowed for containers created by the root user.
-
-**nomap**: creates a user namespace where the current rootless user's UID:GID are not mapped into the container. This option is not allowed for containers created by the root user.
-
-**ns:**_namespace_: run the container in the given existing user namespace.
-
-**private**: create a new namespace for the container.
-
-This option is incompatible with **--gidmap**, **--uidmap**, **--subuidname** and **--subgidname**.
+@@option userns.container
@@option uts.container
diff --git a/docs/source/markdown/podman-kill.1.md.in b/docs/source/markdown/podman-kill.1.md.in
index 2788cc694..46d7f5c6b 100644
--- a/docs/source/markdown/podman-kill.1.md.in
+++ b/docs/source/markdown/podman-kill.1.md.in
@@ -23,10 +23,7 @@ Signal all running and paused containers.
Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
to run containers such as CRI-O, the last started container could be from either of those methods. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines)
-#### **--signal**, **-s**
-
-Signal to send to the container. For more information on Linux signals, refer to *man signal(7)*.
-
+@@option signal
## EXAMPLE
diff --git a/docs/source/markdown/podman-kube-play.1.md.in b/docs/source/markdown/podman-kube-play.1.md.in
index f0b404057..bcd5687ca 100644
--- a/docs/source/markdown/podman-kube-play.1.md.in
+++ b/docs/source/markdown/podman-kube-play.1.md.in
@@ -21,7 +21,7 @@ Currently, the supported Kubernetes kinds are:
`Kubernetes Pods or Deployments`
-Only two volume types are supported by kube play, the *hostPath* and *persistentVolumeClaim* volume types. For the *hostPath* volume type, only the *default (empty)*, *DirectoryOrCreate*, *Directory*, *FileOrCreate*, *File*, *Socket*, *CharDevice* and *BlockDevice* subtypes are supported. Podman interprets the value of *hostPath* *path* as a file path when it contains at least one forward slash, otherwise Podman treats the value as the name of a named volume. When using a *persistentVolumeClaim*, the value for *claimName* is the name for the Podman named volume.
+Only three volume types are supported by kube play, the *hostPath*, *emptyDir*, and *persistentVolumeClaim* volume types. For the *hostPath* volume type, only the *default (empty)*, *DirectoryOrCreate*, *Directory*, *FileOrCreate*, *File*, *Socket*, *CharDevice* and *BlockDevice* subtypes are supported. Podman interprets the value of *hostPath* *path* as a file path when it contains at least one forward slash, otherwise Podman treats the value as the name of a named volume. When using a *persistentVolumeClaim*, the value for *claimName* is the name for the Podman named volume. When using an *emptyDir* volume, podman creates an anonymous volume that is attached the containers running inside the pod and is deleted once the pod is removed.
Note: When playing a kube YAML with init containers, the init container will be created with init type value `once`. To change the default type, use the `io.podman.annotations.init.container.type` annotation to set the type to `always`.
@@ -225,45 +225,7 @@ Require HTTPS and verify certificates when contacting registries (default: true)
then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified,
TLS verification will be used unless the target registry is listed as an insecure registry in registries.conf.
-#### **--userns**=*mode*
-
-Set the user namespace mode for the container. It defaults to the **PODMAN_USERNS** environment variable. An empty value ("") means user namespaces are disabled unless an explicit mapping is set with the **--uidmap** and **--gidmap** options.
-
-Rootless user --userns=Key mappings:
-
-Key | Host User | Container User
-----------|---------------|---------------------
-"" |$UID |0 (Default User account mapped to root user in container.)
-keep-id |$UID |$UID (Map user account to same UID within container.)
-auto |$UID | nil (Host User UID is not mapped into container.)
-nomap |$UID | nil (Host User UID is not mapped into container.)
-
-Valid _mode_ values are:
-
-**auto**[:_OPTIONS,..._]: automatically create a unique user namespace.
-
-The `--userns=auto` flag, requires that the user name `containers` and a range of subordinate user ids that the Podman container is allowed to use be specified in the /etc/subuid and /etc/subgid files.
-
-Example: `containers:2147483647:2147483648`.
-
-Podman allocates unique ranges of UIDs and GIDs from the `containers` subordinate user ids. The size of the ranges is based on the number of UIDs required in the image. The number of UIDs and GIDs can be overridden with the `size` option. The `auto` options currently does not work in rootless mode
-
- Valid `auto` options:
-
- - *gidmapping*=_CONTAINER_GID:HOST_GID:SIZE_: to force a GID mapping to be present in the user namespace.
- - *size*=_SIZE_: to specify an explicit size for the automatic user namespace. e.g. `--userns=auto:size=8192`. If `size` is not specified, `auto` will estimate a size for the user namespace.
- - *uidmapping*=_CONTAINER_UID:HOST_UID:SIZE_: to force a UID mapping to be present in the user namespace.
-
-**container:**_id_: join the user namespace of the specified container.
-
-**host**: create a new namespace for the container.
-
-**keep-id**: creates a user namespace where the current rootless user's UID:GID are mapped to the same values in the container. This option is not allowed for containers created by the root user.
-
-**nomap**: creates a user namespace where the current rootless user's UID:GID are not mapped into the container. This option is not allowed for containers created by the root user.
-
-**ns:**_namespace_: run the pod in the given existing user namespace.
-
+@@option userns.container
## EXAMPLES
Recreate the pod and containers as described in a file called `demo.yml`
diff --git a/docs/source/markdown/podman-machine-init.1.md b/docs/source/markdown/podman-machine-init.1.md
index 07273a111..cf2eeca0b 100644
--- a/docs/source/markdown/podman-machine-init.1.md
+++ b/docs/source/markdown/podman-machine-init.1.md
@@ -76,6 +76,12 @@ Set the timezone for the machine and containers. Valid values are `local` or
a `timezone` such as `America/Chicago`. A value of `local`, which is the default,
means to use the timezone of the machine host.
+#### **--username**
+
+Username to use for executing commands in remote VM. Default value is `core`
+for FCOS and `user` for Fedora (default on Windows hosts). Should match the one
+used inside the resulting VM image.
+
#### **--volume**, **-v**=*source:target[:options]*
Mounts a volume from source to target.
diff --git a/docs/source/markdown/podman-pod-kill.1.md b/docs/source/markdown/podman-pod-kill.1.md.in
index 96ced68a7..7f37661b0 100644
--- a/docs/source/markdown/podman-pod-kill.1.md
+++ b/docs/source/markdown/podman-pod-kill.1.md.in
@@ -19,10 +19,7 @@ Sends signal to all containers associated with a pod.
Instead of providing the pod name or ID, use the last created pod. If you use methods other than Podman
to run pods such as CRI-O, the last started pod could be from either of those methods. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines)
-#### **--signal**, **-s**
-
-Signal to send to the containers in the pod. For more information on Linux signals, refer to *man signal(7)*.
-
+@@option signal
## EXAMPLE
diff --git a/docs/source/markdown/podman-run.1.md.in b/docs/source/markdown/podman-run.1.md.in
index 7c7ce8b3c..c4df88e3b 100644
--- a/docs/source/markdown/podman-run.1.md.in
+++ b/docs/source/markdown/podman-run.1.md.in
@@ -531,21 +531,7 @@ Suppress output information when pulling images
@@option requires
-#### **--restart**=*policy*
-
-Restart policy to follow when containers exit.
-Restart policy will not take effect if a container is stopped via the **podman kill** or **podman stop** commands.
-
-Valid _policy_ values are:
-
-- `no` : Do not restart containers on exit
-- `on-failure[:max_retries]` : Restart containers when they exit with a non-zero exit code, retrying indefinitely or until the optional *max_retries* count is hit
-- `always` : Restart containers when they exit, regardless of status, retrying indefinitely
-- `unless-stopped` : Identical to **always**
-
-Please note that restart will not restart containers after a system reboot.
-If this functionality is required in your environment, you can invoke Podman from a **systemd.unit**(5) file, or create an init script for whichever init system is in use.
-To generate systemd unit files, please see **podman generate systemd**.
+@@option restart
#### **--rm**
@@ -700,49 +686,7 @@ Without this argument, the command will run as the user specified in the contain
When a user namespace is not in use, the UID and GID used within the container and on the host will match. When user namespaces are in use, however, the UID and GID in the container may correspond to another UID and GID on the host. In rootless containers, for example, a user namespace is always used, and root in the container will by default correspond to the UID and GID of the user invoking Podman.
-#### **--userns**=*mode*
-
-Set the user namespace mode for the container. It defaults to the **PODMAN_USERNS** environment variable. An empty value ("") means user namespaces are disabled unless an explicit mapping is set with the **--uidmap** and **--gidmap** options.
-
-Rootless user --userns=Key mappings:
-
-Key | Host User | Container User
-----------|---------------|---------------------
-"" |$UID |0 (Default User account mapped to root user in container.)
-keep-id |$UID |$UID (Map user account to same UID within container.)
-auto |$UID | nil (Host User UID is not mapped into container.)
-nomap |$UID | nil (Host User UID is not mapped into container.)
-
-Valid _mode_ values are:
-
-**auto**[:_OPTIONS,..._]: automatically create a unique user namespace.
-
-The `--userns=auto` flag, requires that the user name `containers` and a range of subordinate user ids that the Podman container is allowed to use be specified in the /etc/subuid and /etc/subgid files.
-
-Example: `containers:2147483647:2147483648`.
-
-Podman allocates unique ranges of UIDs and GIDs from the `containers` subordinate user ids. The size of the ranges is based on the number of UIDs required in the image. The number of UIDs and GIDs can be overridden with the `size` option.
-
-The rootless option `--userns=keep-id` uses all the subuids and subgids of the user. Using `--userns=auto` when starting new containers will not work as long as any containers exist that were started with `--userns=keep-id`.
-
- Valid `auto` options:
-
- - *gidmapping*=_CONTAINER_GID:HOST_GID:SIZE_: to force a GID mapping to be present in the user namespace.
- - *size*=_SIZE_: to specify an explicit size for the automatic user namespace. e.g. `--userns=auto:size=8192`. If `size` is not specified, `auto` will estimate a size for the user namespace.
- - *uidmapping*=_CONTAINER_UID:HOST_UID:SIZE_: to force a UID mapping to be present in the user namespace.
-
-**container:**_id_: join the user namespace of the specified container.
-
-**host**: run in the user namespace of the caller. The processes running in the container will have the same privileges on the host as any other process launched by the calling user (default).
-
-**keep-id**: creates a user namespace where the current rootless user's UID:GID are mapped to the same values in the container. This option is not allowed for containers created by the root user.
-
-**nomap**: creates a user namespace where the current rootless user's UID:GID are not mapped into the container. This option is not allowed for containers created by the root user.
-
-**ns:**_namespace_: run the container in the given existing user namespace.
-
-**private**: create a new namespace for the container.
-This option is incompatible with **--gidmap**, **--uidmap**, **--subuidname** and **--subgidname**.
+@@option userns.container
@@option uts.container
diff --git a/go.mod b/go.mod
index b4830699c..e6fb5a8f1 100644
--- a/go.mod
+++ b/go.mod
@@ -12,7 +12,7 @@ require (
github.com/containernetworking/cni v1.1.2
github.com/containernetworking/plugins v1.1.1
github.com/containers/buildah v1.27.0
- github.com/containers/common v0.49.2-0.20220823130605-72a7da3358ac
+ github.com/containers/common v0.49.2-0.20220826180622-c2dcb4e70340
github.com/containers/conmon v2.0.20+incompatible
github.com/containers/image/v5 v5.22.0
github.com/containers/ocicrypt v1.1.5
diff --git a/go.sum b/go.sum
index fdfb5d0fe..b2a311fbf 100644
--- a/go.sum
+++ b/go.sum
@@ -395,8 +395,8 @@ github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19
github.com/containers/buildah v1.27.0 h1:LJ1ks7vKxwPzJGr5BWVvigbtVL9w7XeHtNEmiIOPJqI=
github.com/containers/buildah v1.27.0/go.mod h1:anH3ExvDXRNP9zLQCrOc1vWb5CrhqLF/aYFim4tslvA=
github.com/containers/common v0.49.1/go.mod h1:ueM5hT0itKqCQvVJDs+EtjornAQtrHYxQJzP2gxeGIg=
-github.com/containers/common v0.49.2-0.20220823130605-72a7da3358ac h1:rLbTzosxPKrQd+EgMRxfC1WYm3azPiQfig+Lr7mCQ4k=
-github.com/containers/common v0.49.2-0.20220823130605-72a7da3358ac/go.mod h1:xC4qkLfW9R+YSDknlT9xU+NDNxIw017U8AyohGtr9Ec=
+github.com/containers/common v0.49.2-0.20220826180622-c2dcb4e70340 h1:Qg3LBb6sp5clQBF9OPqumvlCJGsMl6N2b5hEDttRbWA=
+github.com/containers/common v0.49.2-0.20220826180622-c2dcb4e70340/go.mod h1:xC4qkLfW9R+YSDknlT9xU+NDNxIw017U8AyohGtr9Ec=
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
github.com/containers/image/v5 v5.22.0 h1:KemxPmD4D2YYOFZN2SgoTk7nBFcnwPiPW0MqjYtknSE=
diff --git a/libpod/container.go b/libpod/container.go
index 6c05b1084..44a8669fd 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -237,6 +237,9 @@ type ContainerNamedVolume struct {
Dest string `json:"dest"`
// Options are fstab style mount options
Options []string `json:"options,omitempty"`
+ // IsAnonymous sets the named volume as anonymous even if it has a name
+ // This is used for emptyDir volumes from a kube yaml
+ IsAnonymous bool `json:"setAnonymous,omitempty"`
}
// ContainerOverlayVolume is a overlay volume that will be mounted into the
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 60fb29607..7d390ec21 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -27,6 +27,7 @@ import (
cutil "github.com/containers/common/pkg/util"
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/libpod/events"
+ "github.com/containers/podman/v4/libpod/shutdown"
"github.com/containers/podman/v4/pkg/ctime"
"github.com/containers/podman/v4/pkg/lookup"
"github.com/containers/podman/v4/pkg/rootless"
@@ -1038,6 +1039,13 @@ func (c *Container) init(ctx context.Context, retainRetries bool) error {
}
}
+ // To ensure that we don't lose track of Conmon if hit by a SIGTERM
+ // in the middle of setting up the container, inhibit shutdown signals
+ // until after we save Conmon's PID to the state.
+ // TODO: This can likely be removed once conmon-rs support merges.
+ shutdown.Inhibit()
+ defer shutdown.Uninhibit()
+
// With the spec complete, do an OCI create
if _, err = c.ociRuntime.CreateContainer(c, nil); err != nil {
return err
@@ -1073,6 +1081,7 @@ func (c *Container) init(ctx context.Context, retainRetries bool) error {
if err := c.save(); err != nil {
return err
}
+
if c.config.HealthCheckConfig != nil {
if err := c.createTimer(); err != nil {
logrus.Error(err)
diff --git a/libpod/oci_conmon_freebsd.go b/libpod/oci_conmon_freebsd.go
index 6f7ac7fc6..d74f2af01 100644
--- a/libpod/oci_conmon_freebsd.go
+++ b/libpod/oci_conmon_freebsd.go
@@ -19,6 +19,9 @@ func (r *ConmonOCIRuntime) withContainerSocketLabel(ctr *Container, closure func
// moveConmonToCgroupAndSignal gets a container's cgroupParent and moves the conmon process to that cgroup
// it then signals for conmon to start by sending nonce data down the start fd
func (r *ConmonOCIRuntime) moveConmonToCgroupAndSignal(ctr *Container, cmd *exec.Cmd, startFd *os.File) error {
- // No equivalent on FreeBSD
+ // No equivalent to cgroup on FreeBSD, just signal conmon to start
+ if err := writeConmonPipeData(startFd); err != nil {
+ return err
+ }
return nil
}
diff --git a/libpod/options.go b/libpod/options.go
index d31741094..56d5265d2 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1413,9 +1413,10 @@ func WithNamedVolumes(volumes []*ContainerNamedVolume) CtrCreateOption {
}
ctr.config.NamedVolumes = append(ctr.config.NamedVolumes, &ContainerNamedVolume{
- Name: vol.Name,
- Dest: vol.Dest,
- Options: mountOpts,
+ Name: vol.Name,
+ Dest: vol.Dest,
+ Options: mountOpts,
+ IsAnonymous: vol.IsAnonymous,
})
}
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 703ae5cbe..b43114fab 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -474,6 +474,11 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai
return nil, fmt.Errorf("error retrieving named volume %s for new container: %w", vol.Name, err)
}
}
+ if vol.IsAnonymous {
+ // If SetAnonymous is true, make this an anonymous volume
+ // this is needed for emptyDir volumes from kube yamls
+ isAnonymous = true
+ }
logrus.Debugf("Creating new volume %s for container", vol.Name)
@@ -814,11 +819,11 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force, remo
// Ignore error, since podman will report original error
volumesFrom, _ := c.volumesFrom()
if len(volumesFrom) > 0 {
- logrus.Debugf("Cleaning up volume not possible since volume is in use (%s)", v)
+ logrus.Debugf("Cleaning up volume not possible since volume is in use (%s)", v.Name)
continue
}
}
- logrus.Errorf("Cleaning up volume (%s): %v", v, err)
+ logrus.Errorf("Cleaning up volume (%s): %v", v.Name, err)
}
}
}
@@ -968,7 +973,7 @@ func (r *Runtime) evictContainer(ctx context.Context, idOrName string, removeVol
continue
}
if err := r.removeVolume(ctx, volume, false, timeout, false); err != nil && err != define.ErrNoSuchVolume && err != define.ErrVolumeBeingUsed {
- logrus.Errorf("Cleaning up volume (%s): %v", v, err)
+ logrus.Errorf("Cleaning up volume (%s): %v", v.Name, err)
}
}
}
diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go
index bb7867c4e..ea7d445db 100644
--- a/pkg/bindings/images/images.go
+++ b/pkg/bindings/images/images.go
@@ -282,9 +282,9 @@ func Search(ctx context.Context, term string, options *SearchOptions) ([]entitie
}
params.Set("term", term)
- // Note: we have to verify if skipped is false.
+ // SkipTLSVerify is special. It's not being serialized by ToParams()
+ // because we need to flip the boolean.
if options.SkipTLSVerify != nil {
- params.Del("SkipTLSVerify")
params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
}
diff --git a/pkg/bindings/images/pull.go b/pkg/bindings/images/pull.go
index 109981c63..8caf45c0e 100644
--- a/pkg/bindings/images/pull.go
+++ b/pkg/bindings/images/pull.go
@@ -35,9 +35,9 @@ func Pull(ctx context.Context, rawImage string, options *PullOptions) ([]string,
}
params.Set("reference", rawImage)
+ // SkipTLSVerify is special. It's not being serialized by ToParams()
+ // because we need to flip the boolean.
if options.SkipTLSVerify != nil {
- params.Del("SkipTLSVerify")
- // Note: we have to verify if skipped is false.
params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
}
diff --git a/pkg/bindings/images/push.go b/pkg/bindings/images/push.go
index f1e059f8c..0e1309e91 100644
--- a/pkg/bindings/images/push.go
+++ b/pkg/bindings/images/push.go
@@ -38,10 +38,9 @@ func Push(ctx context.Context, source string, destination string, options *PushO
if err != nil {
return err
}
- // SkipTLSVerify is special. We need to delete the param added by
- // toparams and change the key and flip the bool
+ // SkipTLSVerify is special. It's not being serialized by ToParams()
+ // because we need to flip the boolean.
if options.SkipTLSVerify != nil {
- params.Del("SkipTLSVerify")
params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
}
params.Set("destination", destination)
diff --git a/pkg/bindings/images/types.go b/pkg/bindings/images/types.go
index 3ecfb9e09..f8630926e 100644
--- a/pkg/bindings/images/types.go
+++ b/pkg/bindings/images/types.go
@@ -136,9 +136,9 @@ type PushOptions struct {
// ProgressWriter is a writer where push progress are sent.
// Since API handler for image push is quiet by default, WithQuiet(false) is necessary for
// the writer to receive progress messages.
- ProgressWriter *io.Writer
+ ProgressWriter *io.Writer `schema:"-"`
// SkipTLSVerify to skip HTTPS and certificate verification.
- SkipTLSVerify *bool
+ SkipTLSVerify *bool `schema:"-"`
// RemoveSignatures Discard any pre-existing signatures in the image.
RemoveSignatures *bool
// Username for authenticating against the registry.
@@ -158,7 +158,7 @@ type SearchOptions struct {
// Limit the number of results.
Limit *int
// SkipTLSVerify to skip HTTPS and certificate verification.
- SkipTLSVerify *bool
+ SkipTLSVerify *bool `schema:"-"`
// ListTags search the available tags of the repository
ListTags *bool
}
@@ -183,12 +183,12 @@ type PullOptions struct {
// Password for authenticating against the registry.
Password *string
// ProgressWriter is a writer where pull progress are sent.
- ProgressWriter *io.Writer
+ ProgressWriter *io.Writer `schema:"-"`
// Quiet can be specified to suppress pull progress when pulling. Ignored
// for remote calls.
Quiet *bool
// SkipTLSVerify to skip HTTPS and certificate verification.
- SkipTLSVerify *bool
+ SkipTLSVerify *bool `schema:"-"`
// Username for authenticating against the registry.
Username *string
// Variant will overwrite the local variant for image pulls.
diff --git a/pkg/bindings/internal/util/util.go b/pkg/bindings/internal/util/util.go
index f8f99d6c1..52ce14738 100644
--- a/pkg/bindings/internal/util/util.go
+++ b/pkg/bindings/internal/util/util.go
@@ -74,6 +74,9 @@ func ToParams(o interface{}) (url.Values, error) {
}
paramName := fieldName
if pn, ok := sType.Field(i).Tag.Lookup("schema"); ok {
+ if pn == "-" {
+ continue
+ }
paramName = pn
}
switch {
diff --git a/pkg/bindings/kube/kube.go b/pkg/bindings/kube/kube.go
index e727439cf..1b9f888ef 100644
--- a/pkg/bindings/kube/kube.go
+++ b/pkg/bindings/kube/kube.go
@@ -40,8 +40,10 @@ func PlayWithBody(ctx context.Context, body io.Reader, options *PlayOptions) (*e
if err != nil {
return nil, err
}
+ // SkipTLSVerify is special. It's not being serialized by ToParams()
+ // because we need to flip the boolean.
if options.SkipTLSVerify != nil {
- params.Set("tlsVerify", strconv.FormatBool(options.GetSkipTLSVerify()))
+ params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
}
if options.Start != nil {
params.Set("start", strconv.FormatBool(options.GetStart()))
diff --git a/pkg/bindings/kube/types.go b/pkg/bindings/kube/types.go
index 783d1912a..279a9f8f3 100644
--- a/pkg/bindings/kube/types.go
+++ b/pkg/bindings/kube/types.go
@@ -27,7 +27,7 @@ type PlayOptions struct {
SignaturePolicy *string
// SkipTLSVerify - skip https and certificate validation when
// contacting container registries.
- SkipTLSVerify *bool
+ SkipTLSVerify *bool `schema:"-"`
// SeccompProfileRoot - path to a directory containing seccomp
// profiles.
SeccompProfileRoot *string
diff --git a/pkg/bindings/manifests/manifests.go b/pkg/bindings/manifests/manifests.go
index 0163d21a0..752366937 100644
--- a/pkg/bindings/manifests/manifests.go
+++ b/pkg/bindings/manifests/manifests.go
@@ -165,10 +165,9 @@ func Push(ctx context.Context, name, destination string, options *images.PushOpt
if err != nil {
return "", err
}
- // SkipTLSVerify is special. We need to delete the param added by
- // ToParams() and change the key and flip the bool
+ // SkipTLSVerify is special. It's not being serialized by ToParams()
+ // because we need to flip the boolean.
if options.SkipTLSVerify != nil {
- params.Del("SkipTLSVerify")
params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
}
@@ -246,10 +245,9 @@ func Modify(ctx context.Context, name string, images []string, options *ModifyOp
if err != nil {
return "", err
}
- // SkipTLSVerify is special. We need to delete the param added by
- // ToParams() and change the key and flip the bool
+ // SkipTLSVerify is special. It's not being serialized by ToParams()
+ // because we need to flip the boolean.
if options.SkipTLSVerify != nil {
- params.Del("SkipTLSVerify")
params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
}
diff --git a/pkg/bindings/manifests/types.go b/pkg/bindings/manifests/types.go
index 5f2557fe1..fec3f9d13 100644
--- a/pkg/bindings/manifests/types.go
+++ b/pkg/bindings/manifests/types.go
@@ -32,7 +32,7 @@ type AddOptions struct {
Authfile *string
Password *string
Username *string
- SkipTLSVerify *bool
+ SkipTLSVerify *bool `schema:"-"`
}
//go:generate go run ../generator/generator.go RemoveOptions
@@ -60,5 +60,5 @@ type ModifyOptions struct {
Authfile *string
Password *string
Username *string
- SkipTLSVerify *bool
+ SkipTLSVerify *bool `schema:"-"`
}
diff --git a/pkg/bindings/test/types_test.go b/pkg/bindings/test/types_test.go
new file mode 100644
index 000000000..bc98c8b7d
--- /dev/null
+++ b/pkg/bindings/test/types_test.go
@@ -0,0 +1,66 @@
+package bindings_test
+
+import (
+ "bytes"
+
+ "github.com/containers/podman/v4/pkg/bindings/images"
+ "github.com/containers/podman/v4/pkg/bindings/kube"
+ "github.com/containers/podman/v4/pkg/bindings/manifests"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("Binding types", func() {
+ It("serialize image pull options", func() {
+ var writer bytes.Buffer
+ opts := new(images.PullOptions).WithOS("foo").WithProgressWriter(&writer).WithSkipTLSVerify(true)
+ params, err := opts.ToParams()
+ Expect(err).ToNot(HaveOccurred())
+ Expect(params.Get("os")).To(Equal("foo"))
+ Expect(params.Has("progresswriter")).To(BeFalse())
+ Expect(params.Has("skiptlsverify")).To(BeFalse())
+ })
+
+ It("serialize image push options", func() {
+ var writer bytes.Buffer
+ opts := new(images.PushOptions).WithAll(true).WithProgressWriter(&writer).WithSkipTLSVerify(true)
+ params, err := opts.ToParams()
+ Expect(err).ToNot(HaveOccurred())
+ Expect(params.Get("all")).To(Equal("true"))
+ Expect(params.Has("progresswriter")).To(BeFalse())
+ Expect(params.Has("skiptlsverify")).To(BeFalse())
+ })
+
+ It("serialize image search options", func() {
+ opts := new(images.SearchOptions).WithLimit(123).WithSkipTLSVerify(true)
+ params, err := opts.ToParams()
+ Expect(err).ToNot(HaveOccurred())
+ Expect(params.Get("limit")).To(Equal("123"))
+ Expect(params.Has("skiptlsverify")).To(BeFalse())
+ })
+
+ It("serialize manifest modify options", func() {
+ opts := new(manifests.ModifyOptions).WithOS("foo").WithSkipTLSVerify(true)
+ params, err := opts.ToParams()
+ Expect(err).ToNot(HaveOccurred())
+ Expect(params.Get("os")).To(Equal("foo"))
+ Expect(params.Has("skiptlsverify")).To(BeFalse())
+ })
+
+ It("serialize manifest add options", func() {
+ opts := new(manifests.AddOptions).WithAll(true).WithOS("foo").WithSkipTLSVerify(true)
+ params, err := opts.ToParams()
+ Expect(err).ToNot(HaveOccurred())
+ Expect(params.Get("all")).To(Equal("true"))
+ Expect(params.Get("os")).To(Equal("foo"))
+ Expect(params.Has("skiptlsverify")).To(BeFalse())
+ })
+
+ It("serialize kube play options", func() {
+ opts := new(kube.PlayOptions).WithQuiet(true).WithSkipTLSVerify(true)
+ params, err := opts.ToParams()
+ Expect(err).ToNot(HaveOccurred())
+ Expect(params.Get("quiet")).To(Equal("true"))
+ Expect(params.Has("skiptlsverify")).To(BeFalse())
+ })
+})
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index faa89cc26..6ea20a4f2 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -436,7 +436,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
}
// Go through the volumes and create a podman volume for all volumes that have been
- // defined by a configmap
+ // defined by a configmap or secret
for _, v := range volumes {
if (v.Type == kube.KubeVolumeTypeConfigMap || v.Type == kube.KubeVolumeTypeSecret) && !v.Optional {
vol, err := ic.Libpod.NewVolume(ctx, libpod.WithVolumeName(v.Source))
diff --git a/pkg/domain/infra/runtime_libpod.go b/pkg/domain/infra/runtime_libpod.go
index f76fab4ea..a23a23653 100644
--- a/pkg/domain/infra/runtime_libpod.go
+++ b/pkg/domain/infra/runtime_libpod.go
@@ -294,57 +294,6 @@ func ParseIDMapping(mode namespaces.UsernsMode, uidMapSlice, gidMapSlice []strin
options.AutoUserNsOpts = *opts
return &options, nil
}
- if mode.IsKeepID() {
- if len(uidMapSlice) > 0 || len(gidMapSlice) > 0 {
- return nil, errors.New("cannot specify custom mappings with --userns=keep-id")
- }
- if len(subUIDMap) > 0 || len(subGIDMap) > 0 {
- return nil, errors.New("cannot specify subuidmap or subgidmap with --userns=keep-id")
- }
- if !rootless.IsRootless() {
- return nil, errors.New("keep-id is only supported in rootless mode")
- }
- min := func(a, b int) int {
- if a < b {
- return a
- }
- return b
- }
-
- uid := rootless.GetRootlessUID()
- gid := rootless.GetRootlessGID()
-
- uids, gids, err := rootless.GetConfiguredMappings()
- if err != nil {
- return nil, fmt.Errorf("cannot read mappings: %w", err)
- }
- maxUID, maxGID := 0, 0
- for _, u := range uids {
- maxUID += u.Size
- }
- for _, g := range gids {
- maxGID += g.Size
- }
-
- options.UIDMap, options.GIDMap = nil, nil
-
- options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(uid, maxUID)})
- options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid, HostID: 0, Size: 1})
- if maxUID > uid {
- options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid + 1, HostID: uid + 1, Size: maxUID - uid})
- }
-
- options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(gid, maxGID)})
- options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid, HostID: 0, Size: 1})
- if maxGID > gid {
- options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid + 1, HostID: gid + 1, Size: maxGID - gid})
- }
-
- options.HostUIDMapping = false
- options.HostGIDMapping = false
- // Simply ignore the setting and do not set up an inner namespace for root as it is a no-op
- return &options, nil
- }
if subGIDMap == "" && subUIDMap != "" {
subGIDMap = subUIDMap
diff --git a/pkg/k8s.io/api/core/v1/types.go b/pkg/k8s.io/api/core/v1/types.go
index 384965769..d47178878 100644
--- a/pkg/k8s.io/api/core/v1/types.go
+++ b/pkg/k8s.io/api/core/v1/types.go
@@ -58,6 +58,10 @@ type VolumeSource struct {
ConfigMap *ConfigMapVolumeSource `json:"configMap,omitempty"`
// Secret represents a secret that should be mounted as a volume
Secret *SecretVolumeSource `json:"secret,omitempty"`
+ // emptyDir represents a temporary directory that shares a pod's lifetime.
+ // More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir
+ // +optional
+ EmptyDir *EmptyDirVolumeSource `json:"emptyDir,omitempty"`
}
// PersistentVolumeClaimVolumeSource references the user's PVC in the same namespace.
diff --git a/pkg/machine/e2e/config_init_test.go b/pkg/machine/e2e/config_init_test.go
index d6c7990b0..305d101a3 100644
--- a/pkg/machine/e2e/config_init_test.go
+++ b/pkg/machine/e2e/config_init_test.go
@@ -9,6 +9,7 @@ type initMachine struct {
--cpus uint Number of CPUs (default 1)
--disk-size uint Disk size in GB (default 100)
--ignition-path string Path to ignition file
+ --username string Username of the remote user (default "core" for FCOS, "user" for Fedora)
--image-path string Path to qcow image (default "testing")
-m, --memory uint Memory in MB (default 2048)
--now Start machine now
@@ -21,6 +22,7 @@ type initMachine struct {
cpus *uint
diskSize *uint
ignitionPath string
+ username string
imagePath string
memory *uint
now bool
@@ -42,6 +44,9 @@ func (i *initMachine) buildCmd(m *machineTestBuilder) []string {
if l := len(i.ignitionPath); l > 0 {
cmd = append(cmd, "--ignition-path", i.ignitionPath)
}
+ if l := len(i.username); l > 0 {
+ cmd = append(cmd, "--username", i.username)
+ }
if l := len(i.imagePath); l > 0 {
cmd = append(cmd, "--image-path", i.imagePath)
}
@@ -76,6 +81,11 @@ func (i *initMachine) withIgnitionPath(path string) *initMachine { //nolint:unus
return i
}
+func (i *initMachine) withUsername(username string) *initMachine {
+ i.username = username
+ return i
+}
+
func (i *initMachine) withImagePath(path string) *initMachine {
i.imagePath = path
return i
diff --git a/pkg/machine/e2e/init_test.go b/pkg/machine/e2e/init_test.go
index 859a3ca46..c298d3b14 100644
--- a/pkg/machine/e2e/init_test.go
+++ b/pkg/machine/e2e/init_test.go
@@ -77,6 +77,26 @@ var _ = Describe("podman machine init", func() {
Expect(inspectAfter[0].State).To(Equal(machine.Running))
})
+ It("simple init with username", func() {
+ i := new(initMachine)
+ remoteUsername := "remoteuser"
+ session, err := mb.setCmd(i.withImagePath(mb.imagePath).withUsername(remoteUsername)).run()
+ Expect(err).To(BeNil())
+ Expect(session).To(Exit(0))
+
+ inspectBefore, ec, err := mb.toQemuInspectInfo()
+ Expect(err).To(BeNil())
+ Expect(ec).To(BeZero())
+
+ Expect(len(inspectBefore)).To(BeNumerically(">", 0))
+ testMachine := inspectBefore[0]
+ Expect(testMachine.Name).To(Equal(mb.names[0]))
+ Expect(testMachine.Resources.CPUs).To(Equal(uint64(1)))
+ Expect(testMachine.Resources.Memory).To(Equal(uint64(2048)))
+ Expect(testMachine.SSHConfig.RemoteUsername).To((Equal(remoteUsername)))
+
+ })
+
It("machine init with cpus, disk size, memory, timezone", func() {
name := randomString()
i := new(initMachine)
diff --git a/pkg/namespaces/namespaces.go b/pkg/namespaces/namespaces.go
index 8eacb8da7..6dd576ea5 100644
--- a/pkg/namespaces/namespaces.go
+++ b/pkg/namespaces/namespaces.go
@@ -21,6 +21,14 @@ const (
slirpType = "slirp4netns"
)
+// KeepIDUserNsOptions defines how to keepIDmatically create a user namespace.
+type KeepIDUserNsOptions struct {
+ // UID is the target uid in the user namespace.
+ UID *uint32
+ // GID is the target uid in the user namespace.
+ GID *uint32
+}
+
// CgroupMode represents cgroup mode in the container.
type CgroupMode string
@@ -93,7 +101,8 @@ func (n UsernsMode) IsHost() bool {
// IsKeepID indicates whether container uses a mapping where the (uid, gid) on the host is kept inside of the namespace.
func (n UsernsMode) IsKeepID() bool {
- return n == "keep-id"
+ parts := strings.Split(string(n), ":")
+ return parts[0] == "keep-id"
}
// IsNoMap indicates whether container uses a mapping where the (uid, gid) on the host is not present in the namespace.
@@ -154,6 +163,44 @@ func (n UsernsMode) GetAutoOptions() (*types.AutoUserNsOptions, error) {
return &options, nil
}
+// GetKeepIDOptions returns a KeepIDUserNsOptions with the settings to keepIDmatically set up
+// a user namespace.
+func (n UsernsMode) GetKeepIDOptions() (*KeepIDUserNsOptions, error) {
+ parts := strings.SplitN(string(n), ":", 2)
+ if parts[0] != "keep-id" {
+ return nil, fmt.Errorf("wrong user namespace mode")
+ }
+ options := KeepIDUserNsOptions{}
+ if len(parts) == 1 {
+ return &options, nil
+ }
+ for _, o := range strings.Split(parts[1], ",") {
+ v := strings.SplitN(o, "=", 2)
+ if len(v) != 2 {
+ return nil, fmt.Errorf("invalid option specified: %q", o)
+ }
+ switch v[0] {
+ case "uid":
+ s, err := strconv.ParseUint(v[1], 10, 32)
+ if err != nil {
+ return nil, err
+ }
+ v := uint32(s)
+ options.UID = &v
+ case "gid":
+ s, err := strconv.ParseUint(v[1], 10, 32)
+ if err != nil {
+ return nil, err
+ }
+ v := uint32(s)
+ options.GID = &v
+ default:
+ return nil, fmt.Errorf("unknown option specified: %q", v[0])
+ }
+ }
+ return &options, nil
+}
+
// IsPrivate indicates whether the container uses the a private userns.
func (n UsernsMode) IsPrivate() bool {
return !(n.IsHost() || n.IsContainer())
diff --git a/pkg/specgen/generate/config_unsupported.go b/pkg/specgen/generate/config_unsupported.go
deleted file mode 100644
index a97ae0709..000000000
--- a/pkg/specgen/generate/config_unsupported.go
+++ /dev/null
@@ -1,29 +0,0 @@
-//go:build !linux
-// +build !linux
-
-package generate
-
-import (
- "errors"
-
- "github.com/containers/common/libimage"
- "github.com/containers/podman/v4/pkg/specgen"
- spec "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/opencontainers/runtime-tools/generate"
-)
-
-// DevicesFromPath computes a list of devices
-func DevicesFromPath(g *generate.Generator, devicePath string) error {
- return errors.New("unsupported DevicesFromPath")
-}
-
-func BlockAccessToKernelFilesystems(privileged, pidModeIsHost bool, mask, unmask []string, g *generate.Generator) {
-}
-
-func supportAmbientCapabilities() bool {
- return false
-}
-
-func getSeccompConfig(s *specgen.SpecGenerator, configSpec *spec.Spec, img *libimage.Image) (*spec.LinuxSeccomp, error) {
- return nil, errors.New("not implemented getSeccompConfig")
-}
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index e9cec2873..819800176 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -387,9 +387,10 @@ func createContainerOptions(rt *libpod.Runtime, s *specgen.SpecGenerator, pod *l
var vols []*libpod.ContainerNamedVolume
for _, v := range volumes {
vols = append(vols, &libpod.ContainerNamedVolume{
- Name: v.Name,
- Dest: v.Dest,
- Options: v.Options,
+ Name: v.Name,
+ Dest: v.Dest,
+ Options: v.Options,
+ IsAnonymous: v.IsAnonymous,
})
}
options = append(options, libpod.WithNamedVolumes(vols))
diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go
index e9abf419b..375b719d3 100644
--- a/pkg/specgen/generate/kube/kube.go
+++ b/pkg/specgen/generate/kube/kube.go
@@ -406,8 +406,15 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener
Name: volumeSource.Source,
Options: options,
}
-
s.Volumes = append(s.Volumes, &secretVolume)
+ case KubeVolumeTypeEmptyDir:
+ emptyDirVolume := specgen.NamedVolume{
+ Dest: volume.MountPath,
+ Name: volumeSource.Source,
+ Options: options,
+ IsAnonymous: true,
+ }
+ s.Volumes = append(s.Volumes, &emptyDirVolume)
default:
return nil, errors.New("unsupported volume source type")
}
diff --git a/pkg/specgen/generate/kube/volume.go b/pkg/specgen/generate/kube/volume.go
index c12adadd8..230521ec6 100644
--- a/pkg/specgen/generate/kube/volume.go
+++ b/pkg/specgen/generate/kube/volume.go
@@ -32,6 +32,7 @@ const (
KubeVolumeTypeBlockDevice
KubeVolumeTypeCharDevice
KubeVolumeTypeSecret
+ KubeVolumeTypeEmptyDir
)
//nolint:revive
@@ -219,8 +220,13 @@ func VolumeFromConfigMap(configMapVolumeSource *v1.ConfigMapVolumeSource, config
return kv, nil
}
+// Create a kubeVolume for an emptyDir volume
+func VolumeFromEmptyDir(emptyDirVolumeSource *v1.EmptyDirVolumeSource, name string) (*KubeVolume, error) {
+ return &KubeVolume{Type: KubeVolumeTypeEmptyDir, Source: name}, nil
+}
+
// Create a KubeVolume from one of the supported VolumeSource
-func VolumeFromSource(volumeSource v1.VolumeSource, configMaps []v1.ConfigMap, secretsManager *secrets.SecretsManager) (*KubeVolume, error) {
+func VolumeFromSource(volumeSource v1.VolumeSource, configMaps []v1.ConfigMap, secretsManager *secrets.SecretsManager, volName string) (*KubeVolume, error) {
switch {
case volumeSource.HostPath != nil:
return VolumeFromHostPath(volumeSource.HostPath)
@@ -230,8 +236,10 @@ func VolumeFromSource(volumeSource v1.VolumeSource, configMaps []v1.ConfigMap, s
return VolumeFromConfigMap(volumeSource.ConfigMap, configMaps)
case volumeSource.Secret != nil:
return VolumeFromSecret(volumeSource.Secret, secretsManager)
+ case volumeSource.EmptyDir != nil:
+ return VolumeFromEmptyDir(volumeSource.EmptyDir, volName)
default:
- return nil, errors.New("HostPath, ConfigMap, and PersistentVolumeClaim are currently the only supported VolumeSource")
+ return nil, errors.New("HostPath, ConfigMap, EmptyDir, and PersistentVolumeClaim are currently the only supported VolumeSource")
}
}
@@ -240,7 +248,7 @@ func InitializeVolumes(specVolumes []v1.Volume, configMaps []v1.ConfigMap, secre
volumes := make(map[string]*KubeVolume)
for _, specVolume := range specVolumes {
- volume, err := VolumeFromSource(specVolume.VolumeSource, configMaps, secretsManager)
+ volume, err := VolumeFromSource(specVolume.VolumeSource, configMaps, secretsManager, specVolume.Name)
if err != nil {
return nil, fmt.Errorf("failed to create volume %q: %w", specVolume.Name, err)
}
diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go
index f0d4e9153..f57b6c23c 100644
--- a/pkg/specgen/generate/namespaces.go
+++ b/pkg/specgen/generate/namespaces.go
@@ -3,7 +3,6 @@ package generate
import (
"errors"
"fmt"
- "os"
"strings"
"github.com/containers/common/libimage"
@@ -11,11 +10,11 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v4/libpod"
"github.com/containers/podman/v4/libpod/define"
+ "github.com/containers/podman/v4/pkg/namespaces"
"github.com/containers/podman/v4/pkg/rootless"
"github.com/containers/podman/v4/pkg/specgen"
"github.com/containers/podman/v4/pkg/util"
spec "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/opencontainers/runtime-tools/generate"
"github.com/sirupsen/logrus"
)
@@ -198,12 +197,18 @@ func namespaceOptions(s *specgen.SpecGenerator, rt *libpod.Runtime, pod *libpod.
if !rootless.IsRootless() {
return nil, errors.New("keep-id is only supported in rootless mode")
}
- toReturn = append(toReturn, libpod.WithAddCurrentUserPasswdEntry())
+ opts, err := namespaces.UsernsMode(s.UserNS.String()).GetKeepIDOptions()
+ if err != nil {
+ return nil, err
+ }
+ if opts.UID == nil && opts.GID == nil {
+ toReturn = append(toReturn, libpod.WithAddCurrentUserPasswdEntry())
+ }
// If user is not overridden, set user in the container
// to user running Podman.
if s.User == "" {
- _, uid, gid, err := util.GetKeepIDMapping()
+ _, uid, gid, err := util.GetKeepIDMapping(opts)
if err != nil {
return nil, err
}
@@ -357,153 +362,6 @@ func namespaceOptions(s *specgen.SpecGenerator, rt *libpod.Runtime, pod *libpod.
return toReturn, nil
}
-func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt *libpod.Runtime, pod *libpod.Pod) error {
- // PID
- switch s.PidNS.NSMode {
- case specgen.Path:
- if _, err := os.Stat(s.PidNS.Value); err != nil {
- return fmt.Errorf("cannot find specified PID namespace path: %w", err)
- }
- if err := g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), s.PidNS.Value); err != nil {
- return err
- }
- case specgen.Host:
- if err := g.RemoveLinuxNamespace(string(spec.PIDNamespace)); err != nil {
- return err
- }
- case specgen.Private:
- if err := g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), ""); err != nil {
- return err
- }
- }
-
- // IPC
- switch s.IpcNS.NSMode {
- case specgen.Path:
- if _, err := os.Stat(s.IpcNS.Value); err != nil {
- return fmt.Errorf("cannot find specified IPC namespace path: %w", err)
- }
- if err := g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), s.IpcNS.Value); err != nil {
- return err
- }
- case specgen.Host:
- if err := g.RemoveLinuxNamespace(string(spec.IPCNamespace)); err != nil {
- return err
- }
- case specgen.Private:
- if err := g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), ""); err != nil {
- return err
- }
- }
-
- // UTS
- switch s.UtsNS.NSMode {
- case specgen.Path:
- if _, err := os.Stat(s.UtsNS.Value); err != nil {
- return fmt.Errorf("cannot find specified UTS namespace path: %w", err)
- }
- if err := g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), s.UtsNS.Value); err != nil {
- return err
- }
- case specgen.Host:
- if err := g.RemoveLinuxNamespace(string(spec.UTSNamespace)); err != nil {
- return err
- }
- case specgen.Private:
- if err := g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), ""); err != nil {
- return err
- }
- }
-
- hostname := s.Hostname
- if hostname == "" {
- switch {
- case s.UtsNS.NSMode == specgen.FromPod:
- hostname = pod.Hostname()
- case s.UtsNS.NSMode == specgen.FromContainer:
- utsCtr, err := rt.LookupContainer(s.UtsNS.Value)
- if err != nil {
- return fmt.Errorf("error looking up container to share uts namespace with: %w", err)
- }
- hostname = utsCtr.Hostname()
- case (s.NetNS.NSMode == specgen.Host && hostname == "") || s.UtsNS.NSMode == specgen.Host:
- tmpHostname, err := os.Hostname()
- if err != nil {
- return fmt.Errorf("unable to retrieve hostname of the host: %w", err)
- }
- hostname = tmpHostname
- default:
- logrus.Debug("No hostname set; container's hostname will default to runtime default")
- }
- }
-
- g.RemoveHostname()
- if s.Hostname != "" || s.UtsNS.NSMode != specgen.Host {
- // Set the hostname in the OCI configuration only if specified by
- // the user or if we are creating a new UTS namespace.
- // TODO: Should we be doing this for pod or container shared
- // namespaces?
- g.SetHostname(hostname)
- }
- if _, ok := s.Env["HOSTNAME"]; !ok && s.Hostname != "" {
- g.AddProcessEnv("HOSTNAME", hostname)
- }
-
- // User
- if _, err := specgen.SetupUserNS(s.IDMappings, s.UserNS, g); err != nil {
- return err
- }
-
- // Cgroup
- switch s.CgroupNS.NSMode {
- case specgen.Path:
- if _, err := os.Stat(s.CgroupNS.Value); err != nil {
- return fmt.Errorf("cannot find specified cgroup namespace path: %w", err)
- }
- if err := g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), s.CgroupNS.Value); err != nil {
- return err
- }
- case specgen.Host:
- if err := g.RemoveLinuxNamespace(string(spec.CgroupNamespace)); err != nil {
- return err
- }
- case specgen.Private:
- if err := g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), ""); err != nil {
- return err
- }
- }
-
- // Net
- switch s.NetNS.NSMode {
- case specgen.Path:
- if _, err := os.Stat(s.NetNS.Value); err != nil {
- return fmt.Errorf("cannot find specified network namespace path: %w", err)
- }
- if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), s.NetNS.Value); err != nil {
- return err
- }
- case specgen.Host:
- if err := g.RemoveLinuxNamespace(string(spec.NetworkNamespace)); err != nil {
- return err
- }
- case specgen.Private, specgen.NoNetwork:
- if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), ""); err != nil {
- return err
- }
- }
-
- if g.Config.Annotations == nil {
- g.Config.Annotations = make(map[string]string)
- }
- if s.PublishExposedPorts {
- g.Config.Annotations[define.InspectAnnotationPublishAll] = define.InspectResponseTrue
- } else {
- g.Config.Annotations[define.InspectAnnotationPublishAll] = define.InspectResponseFalse
- }
-
- return nil
-}
-
// GetNamespaceOptions transforms a slice of kernel namespaces
// into a slice of pod create options. Currently, not all
// kernel namespaces are supported, and they will be returned in an error
diff --git a/pkg/specgen/generate/namespaces_freebsd.go b/pkg/specgen/generate/namespaces_freebsd.go
new file mode 100644
index 000000000..d821d9daa
--- /dev/null
+++ b/pkg/specgen/generate/namespaces_freebsd.go
@@ -0,0 +1,51 @@
+package generate
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/containers/podman/v4/libpod"
+ "github.com/containers/podman/v4/pkg/specgen"
+ "github.com/opencontainers/runtime-tools/generate"
+ "github.com/sirupsen/logrus"
+)
+
+func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt *libpod.Runtime, pod *libpod.Pod) error {
+ // UTS
+
+ hostname := s.Hostname
+ if hostname == "" {
+ switch {
+ case s.UtsNS.NSMode == specgen.FromPod:
+ hostname = pod.Hostname()
+ case s.UtsNS.NSMode == specgen.FromContainer:
+ utsCtr, err := rt.LookupContainer(s.UtsNS.Value)
+ if err != nil {
+ return fmt.Errorf("error looking up container to share uts namespace with: %w", err)
+ }
+ hostname = utsCtr.Hostname()
+ case (s.NetNS.NSMode == specgen.Host && hostname == "") || s.UtsNS.NSMode == specgen.Host:
+ tmpHostname, err := os.Hostname()
+ if err != nil {
+ return fmt.Errorf("unable to retrieve hostname of the host: %w", err)
+ }
+ hostname = tmpHostname
+ default:
+ logrus.Debug("No hostname set; container's hostname will default to runtime default")
+ }
+ }
+
+ g.RemoveHostname()
+ if s.Hostname != "" || s.UtsNS.NSMode != specgen.Host {
+ // Set the hostname in the OCI configuration only if specified by
+ // the user or if we are creating a new UTS namespace.
+ // TODO: Should we be doing this for pod or container shared
+ // namespaces?
+ g.SetHostname(hostname)
+ }
+ if _, ok := s.Env["HOSTNAME"]; !ok && s.Hostname != "" {
+ g.AddProcessEnv("HOSTNAME", hostname)
+ }
+
+ return nil
+}
diff --git a/pkg/specgen/generate/namespaces_linux.go b/pkg/specgen/generate/namespaces_linux.go
new file mode 100644
index 000000000..5c056e52c
--- /dev/null
+++ b/pkg/specgen/generate/namespaces_linux.go
@@ -0,0 +1,160 @@
+package generate
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/containers/podman/v4/libpod"
+ "github.com/containers/podman/v4/libpod/define"
+ "github.com/containers/podman/v4/pkg/specgen"
+ spec "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/opencontainers/runtime-tools/generate"
+ "github.com/sirupsen/logrus"
+)
+
+func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt *libpod.Runtime, pod *libpod.Pod) error {
+ // PID
+ switch s.PidNS.NSMode {
+ case specgen.Path:
+ if _, err := os.Stat(s.PidNS.Value); err != nil {
+ return fmt.Errorf("cannot find specified PID namespace path: %w", err)
+ }
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), s.PidNS.Value); err != nil {
+ return err
+ }
+ case specgen.Host:
+ if err := g.RemoveLinuxNamespace(string(spec.PIDNamespace)); err != nil {
+ return err
+ }
+ case specgen.Private:
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), ""); err != nil {
+ return err
+ }
+ }
+
+ // IPC
+ switch s.IpcNS.NSMode {
+ case specgen.Path:
+ if _, err := os.Stat(s.IpcNS.Value); err != nil {
+ return fmt.Errorf("cannot find specified IPC namespace path: %w", err)
+ }
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), s.IpcNS.Value); err != nil {
+ return err
+ }
+ case specgen.Host:
+ if err := g.RemoveLinuxNamespace(string(spec.IPCNamespace)); err != nil {
+ return err
+ }
+ case specgen.Private:
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), ""); err != nil {
+ return err
+ }
+ }
+
+ // UTS
+ switch s.UtsNS.NSMode {
+ case specgen.Path:
+ if _, err := os.Stat(s.UtsNS.Value); err != nil {
+ return fmt.Errorf("cannot find specified UTS namespace path: %w", err)
+ }
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), s.UtsNS.Value); err != nil {
+ return err
+ }
+ case specgen.Host:
+ if err := g.RemoveLinuxNamespace(string(spec.UTSNamespace)); err != nil {
+ return err
+ }
+ case specgen.Private:
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), ""); err != nil {
+ return err
+ }
+ }
+
+ hostname := s.Hostname
+ if hostname == "" {
+ switch {
+ case s.UtsNS.NSMode == specgen.FromPod:
+ hostname = pod.Hostname()
+ case s.UtsNS.NSMode == specgen.FromContainer:
+ utsCtr, err := rt.LookupContainer(s.UtsNS.Value)
+ if err != nil {
+ return fmt.Errorf("error looking up container to share uts namespace with: %w", err)
+ }
+ hostname = utsCtr.Hostname()
+ case (s.NetNS.NSMode == specgen.Host && hostname == "") || s.UtsNS.NSMode == specgen.Host:
+ tmpHostname, err := os.Hostname()
+ if err != nil {
+ return fmt.Errorf("unable to retrieve hostname of the host: %w", err)
+ }
+ hostname = tmpHostname
+ default:
+ logrus.Debug("No hostname set; container's hostname will default to runtime default")
+ }
+ }
+
+ g.RemoveHostname()
+ if s.Hostname != "" || s.UtsNS.NSMode != specgen.Host {
+ // Set the hostname in the OCI configuration only if specified by
+ // the user or if we are creating a new UTS namespace.
+ // TODO: Should we be doing this for pod or container shared
+ // namespaces?
+ g.SetHostname(hostname)
+ }
+ if _, ok := s.Env["HOSTNAME"]; !ok && s.Hostname != "" {
+ g.AddProcessEnv("HOSTNAME", hostname)
+ }
+
+ // User
+ if _, err := specgen.SetupUserNS(s.IDMappings, s.UserNS, g); err != nil {
+ return err
+ }
+
+ // Cgroup
+ switch s.CgroupNS.NSMode {
+ case specgen.Path:
+ if _, err := os.Stat(s.CgroupNS.Value); err != nil {
+ return fmt.Errorf("cannot find specified cgroup namespace path: %w", err)
+ }
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), s.CgroupNS.Value); err != nil {
+ return err
+ }
+ case specgen.Host:
+ if err := g.RemoveLinuxNamespace(string(spec.CgroupNamespace)); err != nil {
+ return err
+ }
+ case specgen.Private:
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), ""); err != nil {
+ return err
+ }
+ }
+
+ // Net
+ switch s.NetNS.NSMode {
+ case specgen.Path:
+ if _, err := os.Stat(s.NetNS.Value); err != nil {
+ return fmt.Errorf("cannot find specified network namespace path: %w", err)
+ }
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), s.NetNS.Value); err != nil {
+ return err
+ }
+ case specgen.Host:
+ if err := g.RemoveLinuxNamespace(string(spec.NetworkNamespace)); err != nil {
+ return err
+ }
+ case specgen.Private, specgen.NoNetwork:
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), ""); err != nil {
+ return err
+ }
+ }
+
+ if g.Config.Annotations == nil {
+ g.Config.Annotations = make(map[string]string)
+ }
+ if s.PublishExposedPorts {
+ g.Config.Annotations[define.InspectAnnotationPublishAll] = define.InspectResponseTrue
+ } else {
+ g.Config.Annotations[define.InspectAnnotationPublishAll] = define.InspectResponseFalse
+ }
+
+ return nil
+}
diff --git a/pkg/specgen/generate/namespaces_unsupported.go b/pkg/specgen/generate/namespaces_unsupported.go
new file mode 100644
index 000000000..c4a9c22d8
--- /dev/null
+++ b/pkg/specgen/generate/namespaces_unsupported.go
@@ -0,0 +1,16 @@
+//go:build !linux && !freebsd
+// +build !linux,!freebsd
+
+package generate
+
+import (
+ "errors"
+
+ "github.com/containers/podman/v4/libpod"
+ "github.com/containers/podman/v4/pkg/specgen"
+ "github.com/opencontainers/runtime-tools/generate"
+)
+
+func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt *libpod.Runtime, pod *libpod.Pod) error {
+ return errors.New("unsupported specConfigureNamespaces")
+}
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index a531494c9..3ac1a9b3f 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -1,37 +1,19 @@
package generate
import (
- "context"
- "encoding/json"
"fmt"
- "path"
"strings"
"github.com/containers/common/libimage"
- "github.com/containers/common/pkg/cgroups"
"github.com/containers/common/pkg/config"
- "github.com/containers/podman/v4/libpod"
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/rootless"
"github.com/containers/podman/v4/pkg/specgen"
- spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
-func setProcOpts(s *specgen.SpecGenerator, g *generate.Generator) {
- if s.ProcOpts == nil {
- return
- }
- for i := range g.Config.Mounts {
- if g.Config.Mounts[i].Destination == "/proc" {
- g.Config.Mounts[i].Options = s.ProcOpts
- return
- }
- }
-}
-
func addRlimits(s *specgen.SpecGenerator, g *generate.Generator) {
var (
isRootless = rootless.IsRootless()
@@ -133,302 +115,3 @@ func makeCommand(s *specgen.SpecGenerator, imageData *libimage.ImageData, rtc *c
return finalCommand, nil
}
-
-// canMountSys is a best-effort heuristic to detect whether mounting a new sysfs is permitted in the container
-func canMountSys(isRootless, isNewUserns bool, s *specgen.SpecGenerator) bool {
- if s.NetNS.IsHost() && (isRootless || isNewUserns) {
- return false
- }
- if isNewUserns {
- switch s.NetNS.NSMode {
- case specgen.Slirp, specgen.Private, specgen.NoNetwork, specgen.Bridge:
- return true
- default:
- return false
- }
- }
- return true
-}
-
-func getCgroupPermissons(unmask []string) string {
- ro := "ro"
- rw := "rw"
- cgroup := "/sys/fs/cgroup"
-
- cgroupv2, _ := cgroups.IsCgroup2UnifiedMode()
- if !cgroupv2 {
- return ro
- }
-
- if unmask != nil && unmask[0] == "ALL" {
- return rw
- }
-
- for _, p := range unmask {
- if path.Clean(p) == cgroup {
- return rw
- }
- }
- return ro
-}
-
-// SpecGenToOCI returns the base configuration for the container.
-func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, newImage *libimage.Image, mounts []spec.Mount, pod *libpod.Pod, finalCmd []string, compatibleOptions *libpod.InfraInherit) (*spec.Spec, error) {
- cgroupPerm := getCgroupPermissons(s.Unmask)
-
- g, err := generate.New("linux")
- if err != nil {
- return nil, err
- }
- // Remove the default /dev/shm mount to ensure we overwrite it
- g.RemoveMount("/dev/shm")
- g.HostSpecific = true
- addCgroup := true
-
- isRootless := rootless.IsRootless()
- isNewUserns := s.UserNS.IsContainer() || s.UserNS.IsPath() || s.UserNS.IsPrivate()
-
- canMountSys := canMountSys(isRootless, isNewUserns, s)
-
- if s.Privileged && canMountSys {
- cgroupPerm = "rw"
- g.RemoveMount("/sys")
- sysMnt := spec.Mount{
- Destination: "/sys",
- Type: "sysfs",
- Source: "sysfs",
- Options: []string{"rprivate", "nosuid", "noexec", "nodev", "rw"},
- }
- g.AddMount(sysMnt)
- }
- if !canMountSys {
- addCgroup = false
- g.RemoveMount("/sys")
- r := "ro"
- if s.Privileged {
- r = "rw"
- }
- sysMnt := spec.Mount{
- Destination: "/sys",
- Type: "bind", // should we use a constant for this, like createconfig?
- Source: "/sys",
- Options: []string{"rprivate", "nosuid", "noexec", "nodev", r, "rbind"},
- }
- g.AddMount(sysMnt)
- if !s.Privileged && isRootless {
- g.AddLinuxMaskedPaths("/sys/kernel")
- }
- }
- gid5Available := true
- if isRootless {
- nGids, err := rootless.GetAvailableGids()
- if err != nil {
- return nil, err
- }
- gid5Available = nGids >= 5
- }
- // When using a different user namespace, check that the GID 5 is mapped inside
- // the container.
- if gid5Available && (s.IDMappings != nil && len(s.IDMappings.GIDMap) > 0) {
- mappingFound := false
- for _, r := range s.IDMappings.GIDMap {
- if r.ContainerID <= 5 && 5 < r.ContainerID+r.Size {
- mappingFound = true
- break
- }
- }
- if !mappingFound {
- gid5Available = false
- }
- }
- if !gid5Available {
- // If we have no GID mappings, the gid=5 default option would fail, so drop it.
- g.RemoveMount("/dev/pts")
- devPts := spec.Mount{
- Destination: "/dev/pts",
- Type: "devpts",
- Source: "devpts",
- Options: []string{"rprivate", "nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620"},
- }
- g.AddMount(devPts)
- }
-
- inUserNS := isRootless || isNewUserns
-
- if inUserNS && s.IpcNS.IsHost() {
- g.RemoveMount("/dev/mqueue")
- devMqueue := spec.Mount{
- Destination: "/dev/mqueue",
- Type: "bind", // constant ?
- Source: "/dev/mqueue",
- Options: []string{"bind", "nosuid", "noexec", "nodev"},
- }
- g.AddMount(devMqueue)
- }
- if inUserNS && s.PidNS.IsHost() {
- g.RemoveMount("/proc")
- procMount := spec.Mount{
- Destination: "/proc",
- Type: define.TypeBind,
- Source: "/proc",
- Options: []string{"rbind", "nosuid", "noexec", "nodev"},
- }
- g.AddMount(procMount)
- }
-
- if addCgroup {
- cgroupMnt := spec.Mount{
- Destination: "/sys/fs/cgroup",
- Type: "cgroup",
- Source: "cgroup",
- Options: []string{"rprivate", "nosuid", "noexec", "nodev", "relatime", cgroupPerm},
- }
- g.AddMount(cgroupMnt)
- }
-
- g.Config.Linux.Personality = s.Personality
-
- g.SetProcessCwd(s.WorkDir)
-
- g.SetProcessArgs(finalCmd)
-
- g.SetProcessTerminal(s.Terminal)
-
- for key, val := range s.Annotations {
- g.AddAnnotation(key, val)
- }
-
- if s.ResourceLimits != nil {
- out, err := json.Marshal(s.ResourceLimits)
- if err != nil {
- return nil, err
- }
- err = json.Unmarshal(out, g.Config.Linux.Resources)
- if err != nil {
- return nil, err
- }
- g.Config.Linux.Resources = s.ResourceLimits
- }
-
- weightDevices, err := WeightDevices(s.WeightDevice)
- if err != nil {
- return nil, err
- }
- if len(weightDevices) > 0 {
- for _, dev := range weightDevices {
- g.AddLinuxResourcesBlockIOWeightDevice(dev.Major, dev.Minor, *dev.Weight)
- }
- }
-
- // Devices
- // set the default rule at the beginning of device configuration
- if !inUserNS && !s.Privileged {
- g.AddLinuxResourcesDevice(false, "", nil, nil, "rwm")
- }
-
- var userDevices []spec.LinuxDevice
-
- if !s.Privileged {
- // add default devices from containers.conf
- for _, device := range rtc.Containers.Devices {
- if err = DevicesFromPath(&g, device); err != nil {
- return nil, err
- }
- }
- if len(compatibleOptions.HostDeviceList) > 0 && len(s.Devices) == 0 {
- userDevices = compatibleOptions.HostDeviceList
- } else {
- userDevices = s.Devices
- }
- // add default devices specified by caller
- for _, device := range userDevices {
- if err = DevicesFromPath(&g, device.Path); err != nil {
- return nil, err
- }
- }
- }
- s.HostDeviceList = userDevices
-
- // set the devices cgroup when not running in a user namespace
- if !inUserNS && !s.Privileged {
- for _, dev := range s.DeviceCgroupRule {
- g.AddLinuxResourcesDevice(true, dev.Type, dev.Major, dev.Minor, dev.Access)
- }
- }
-
- BlockAccessToKernelFilesystems(s.Privileged, s.PidNS.IsHost(), s.Mask, s.Unmask, &g)
-
- g.ClearProcessEnv()
- for name, val := range s.Env {
- g.AddProcessEnv(name, val)
- }
-
- addRlimits(s, &g)
-
- // NAMESPACES
- if err := specConfigureNamespaces(s, &g, rt, pod); err != nil {
- return nil, err
- }
- configSpec := g.Config
-
- if err := securityConfigureGenerator(s, &g, newImage, rtc); err != nil {
- return nil, err
- }
-
- // BIND MOUNTS
- configSpec.Mounts = SupersedeUserMounts(mounts, configSpec.Mounts)
- // Process mounts to ensure correct options
- if err := InitFSMounts(configSpec.Mounts); err != nil {
- return nil, err
- }
-
- // Add annotations
- if configSpec.Annotations == nil {
- configSpec.Annotations = make(map[string]string)
- }
-
- if s.Remove {
- configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseTrue
- } else {
- configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseFalse
- }
-
- if len(s.VolumesFrom) > 0 {
- configSpec.Annotations[define.InspectAnnotationVolumesFrom] = strings.Join(s.VolumesFrom, ",")
- }
-
- if s.Privileged {
- configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseTrue
- } else {
- configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseFalse
- }
-
- if s.Init {
- configSpec.Annotations[define.InspectAnnotationInit] = define.InspectResponseTrue
- } else {
- configSpec.Annotations[define.InspectAnnotationInit] = define.InspectResponseFalse
- }
-
- if s.OOMScoreAdj != nil {
- g.SetProcessOOMScoreAdj(*s.OOMScoreAdj)
- }
- setProcOpts(s, &g)
-
- return configSpec, nil
-}
-
-func WeightDevices(wtDevices map[string]spec.LinuxWeightDevice) ([]spec.LinuxWeightDevice, error) {
- devs := []spec.LinuxWeightDevice{}
- for k, v := range wtDevices {
- statT := unix.Stat_t{}
- if err := unix.Stat(k, &statT); err != nil {
- return nil, fmt.Errorf("failed to inspect '%s' in --blkio-weight-device: %w", k, err)
- }
- dev := new(spec.LinuxWeightDevice)
- dev.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
- dev.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
- dev.Weight = v.Weight
- devs = append(devs, *dev)
- }
- return devs, nil
-}
diff --git a/pkg/specgen/generate/oci_freebsd.go b/pkg/specgen/generate/oci_freebsd.go
new file mode 100644
index 000000000..71c926fd2
--- /dev/null
+++ b/pkg/specgen/generate/oci_freebsd.go
@@ -0,0 +1,96 @@
+//go:build freebsd
+
+package generate
+
+import (
+ "context"
+ "strings"
+
+ "github.com/containers/common/libimage"
+ "github.com/containers/common/pkg/config"
+ "github.com/containers/podman/v4/libpod"
+ "github.com/containers/podman/v4/libpod/define"
+ "github.com/containers/podman/v4/pkg/specgen"
+ spec "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/opencontainers/runtime-tools/generate"
+)
+
+// SpecGenToOCI returns the base configuration for the container.
+func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, newImage *libimage.Image, mounts []spec.Mount, pod *libpod.Pod, finalCmd []string, compatibleOptions *libpod.InfraInherit) (*spec.Spec, error) {
+ g, err := generate.New("freebsd")
+ if err != nil {
+ return nil, err
+ }
+
+ g.SetProcessCwd(s.WorkDir)
+
+ g.SetProcessArgs(finalCmd)
+
+ g.SetProcessTerminal(s.Terminal)
+
+ for key, val := range s.Annotations {
+ g.AddAnnotation(key, val)
+ }
+
+ g.ClearProcessEnv()
+ for name, val := range s.Env {
+ g.AddProcessEnv(name, val)
+ }
+
+ addRlimits(s, &g)
+
+ // NAMESPACES
+ if err := specConfigureNamespaces(s, &g, rt, pod); err != nil {
+ return nil, err
+ }
+ configSpec := g.Config
+
+ if err := securityConfigureGenerator(s, &g, newImage, rtc); err != nil {
+ return nil, err
+ }
+
+ // BIND MOUNTS
+ configSpec.Mounts = SupersedeUserMounts(mounts, configSpec.Mounts)
+ // Process mounts to ensure correct options
+ if err := InitFSMounts(configSpec.Mounts); err != nil {
+ return nil, err
+ }
+
+ // Add annotations
+ if configSpec.Annotations == nil {
+ configSpec.Annotations = make(map[string]string)
+ }
+
+ if s.Remove {
+ configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseTrue
+ } else {
+ configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseFalse
+ }
+
+ if len(s.VolumesFrom) > 0 {
+ configSpec.Annotations[define.InspectAnnotationVolumesFrom] = strings.Join(s.VolumesFrom, ",")
+ }
+
+ if s.Privileged {
+ configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseTrue
+ } else {
+ configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseFalse
+ }
+
+ if s.Init {
+ configSpec.Annotations[define.InspectAnnotationInit] = define.InspectResponseTrue
+ } else {
+ configSpec.Annotations[define.InspectAnnotationInit] = define.InspectResponseFalse
+ }
+
+ if s.OOMScoreAdj != nil {
+ g.SetProcessOOMScoreAdj(*s.OOMScoreAdj)
+ }
+
+ return configSpec, nil
+}
+
+func WeightDevices(wtDevices map[string]spec.LinuxWeightDevice) ([]spec.LinuxWeightDevice, error) {
+ devs := []spec.LinuxWeightDevice{}
+ return devs, nil
+}
diff --git a/pkg/specgen/generate/oci_linux.go b/pkg/specgen/generate/oci_linux.go
new file mode 100644
index 000000000..341853de5
--- /dev/null
+++ b/pkg/specgen/generate/oci_linux.go
@@ -0,0 +1,331 @@
+package generate
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "path"
+ "strings"
+
+ "github.com/containers/common/libimage"
+ "github.com/containers/common/pkg/cgroups"
+ "github.com/containers/common/pkg/config"
+ "github.com/containers/podman/v4/libpod"
+ "github.com/containers/podman/v4/libpod/define"
+ "github.com/containers/podman/v4/pkg/rootless"
+ "github.com/containers/podman/v4/pkg/specgen"
+ spec "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/opencontainers/runtime-tools/generate"
+ "golang.org/x/sys/unix"
+)
+
+func setProcOpts(s *specgen.SpecGenerator, g *generate.Generator) {
+ if s.ProcOpts == nil {
+ return
+ }
+ for i := range g.Config.Mounts {
+ if g.Config.Mounts[i].Destination == "/proc" {
+ g.Config.Mounts[i].Options = s.ProcOpts
+ return
+ }
+ }
+}
+
+// canMountSys is a best-effort heuristic to detect whether mounting a new sysfs is permitted in the container
+func canMountSys(isRootless, isNewUserns bool, s *specgen.SpecGenerator) bool {
+ if s.NetNS.IsHost() && (isRootless || isNewUserns) {
+ return false
+ }
+ if isNewUserns {
+ switch s.NetNS.NSMode {
+ case specgen.Slirp, specgen.Private, specgen.NoNetwork, specgen.Bridge:
+ return true
+ default:
+ return false
+ }
+ }
+ return true
+}
+
+func getCgroupPermissons(unmask []string) string {
+ ro := "ro"
+ rw := "rw"
+ cgroup := "/sys/fs/cgroup"
+
+ cgroupv2, _ := cgroups.IsCgroup2UnifiedMode()
+ if !cgroupv2 {
+ return ro
+ }
+
+ if unmask != nil && unmask[0] == "ALL" {
+ return rw
+ }
+
+ for _, p := range unmask {
+ if path.Clean(p) == cgroup {
+ return rw
+ }
+ }
+ return ro
+}
+
+// SpecGenToOCI returns the base configuration for the container.
+func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, newImage *libimage.Image, mounts []spec.Mount, pod *libpod.Pod, finalCmd []string, compatibleOptions *libpod.InfraInherit) (*spec.Spec, error) {
+ cgroupPerm := getCgroupPermissons(s.Unmask)
+
+ g, err := generate.New("linux")
+ if err != nil {
+ return nil, err
+ }
+ // Remove the default /dev/shm mount to ensure we overwrite it
+ g.RemoveMount("/dev/shm")
+ g.HostSpecific = true
+ addCgroup := true
+
+ isRootless := rootless.IsRootless()
+ isNewUserns := s.UserNS.IsContainer() || s.UserNS.IsPath() || s.UserNS.IsPrivate()
+
+ canMountSys := canMountSys(isRootless, isNewUserns, s)
+
+ if s.Privileged && canMountSys {
+ cgroupPerm = "rw"
+ g.RemoveMount("/sys")
+ sysMnt := spec.Mount{
+ Destination: "/sys",
+ Type: "sysfs",
+ Source: "sysfs",
+ Options: []string{"rprivate", "nosuid", "noexec", "nodev", "rw"},
+ }
+ g.AddMount(sysMnt)
+ }
+ if !canMountSys {
+ addCgroup = false
+ g.RemoveMount("/sys")
+ r := "ro"
+ if s.Privileged {
+ r = "rw"
+ }
+ sysMnt := spec.Mount{
+ Destination: "/sys",
+ Type: "bind", // should we use a constant for this, like createconfig?
+ Source: "/sys",
+ Options: []string{"rprivate", "nosuid", "noexec", "nodev", r, "rbind"},
+ }
+ g.AddMount(sysMnt)
+ if !s.Privileged && isRootless {
+ g.AddLinuxMaskedPaths("/sys/kernel")
+ }
+ }
+ gid5Available := true
+ if isRootless {
+ nGids, err := rootless.GetAvailableGids()
+ if err != nil {
+ return nil, err
+ }
+ gid5Available = nGids >= 5
+ }
+ // When using a different user namespace, check that the GID 5 is mapped inside
+ // the container.
+ if gid5Available && (s.IDMappings != nil && len(s.IDMappings.GIDMap) > 0) {
+ mappingFound := false
+ for _, r := range s.IDMappings.GIDMap {
+ if r.ContainerID <= 5 && 5 < r.ContainerID+r.Size {
+ mappingFound = true
+ break
+ }
+ }
+ if !mappingFound {
+ gid5Available = false
+ }
+ }
+ if !gid5Available {
+ // If we have no GID mappings, the gid=5 default option would fail, so drop it.
+ g.RemoveMount("/dev/pts")
+ devPts := spec.Mount{
+ Destination: "/dev/pts",
+ Type: "devpts",
+ Source: "devpts",
+ Options: []string{"rprivate", "nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620"},
+ }
+ g.AddMount(devPts)
+ }
+
+ inUserNS := isRootless || isNewUserns
+
+ if inUserNS && s.IpcNS.IsHost() {
+ g.RemoveMount("/dev/mqueue")
+ devMqueue := spec.Mount{
+ Destination: "/dev/mqueue",
+ Type: "bind", // constant ?
+ Source: "/dev/mqueue",
+ Options: []string{"bind", "nosuid", "noexec", "nodev"},
+ }
+ g.AddMount(devMqueue)
+ }
+ if inUserNS && s.PidNS.IsHost() {
+ g.RemoveMount("/proc")
+ procMount := spec.Mount{
+ Destination: "/proc",
+ Type: define.TypeBind,
+ Source: "/proc",
+ Options: []string{"rbind", "nosuid", "noexec", "nodev"},
+ }
+ g.AddMount(procMount)
+ }
+
+ if addCgroup {
+ cgroupMnt := spec.Mount{
+ Destination: "/sys/fs/cgroup",
+ Type: "cgroup",
+ Source: "cgroup",
+ Options: []string{"rprivate", "nosuid", "noexec", "nodev", "relatime", cgroupPerm},
+ }
+ g.AddMount(cgroupMnt)
+ }
+
+ g.Config.Linux.Personality = s.Personality
+
+ g.SetProcessCwd(s.WorkDir)
+
+ g.SetProcessArgs(finalCmd)
+
+ g.SetProcessTerminal(s.Terminal)
+
+ for key, val := range s.Annotations {
+ g.AddAnnotation(key, val)
+ }
+
+ if s.ResourceLimits != nil {
+ out, err := json.Marshal(s.ResourceLimits)
+ if err != nil {
+ return nil, err
+ }
+ err = json.Unmarshal(out, g.Config.Linux.Resources)
+ if err != nil {
+ return nil, err
+ }
+ g.Config.Linux.Resources = s.ResourceLimits
+ }
+
+ weightDevices, err := WeightDevices(s.WeightDevice)
+ if err != nil {
+ return nil, err
+ }
+ if len(weightDevices) > 0 {
+ for _, dev := range weightDevices {
+ g.AddLinuxResourcesBlockIOWeightDevice(dev.Major, dev.Minor, *dev.Weight)
+ }
+ }
+
+ // Devices
+ // set the default rule at the beginning of device configuration
+ if !inUserNS && !s.Privileged {
+ g.AddLinuxResourcesDevice(false, "", nil, nil, "rwm")
+ }
+
+ var userDevices []spec.LinuxDevice
+
+ if !s.Privileged {
+ // add default devices from containers.conf
+ for _, device := range rtc.Containers.Devices {
+ if err = DevicesFromPath(&g, device); err != nil {
+ return nil, err
+ }
+ }
+ if len(compatibleOptions.HostDeviceList) > 0 && len(s.Devices) == 0 {
+ userDevices = compatibleOptions.HostDeviceList
+ } else {
+ userDevices = s.Devices
+ }
+ // add default devices specified by caller
+ for _, device := range userDevices {
+ if err = DevicesFromPath(&g, device.Path); err != nil {
+ return nil, err
+ }
+ }
+ }
+ s.HostDeviceList = userDevices
+
+ // set the devices cgroup when not running in a user namespace
+ if !inUserNS && !s.Privileged {
+ for _, dev := range s.DeviceCgroupRule {
+ g.AddLinuxResourcesDevice(true, dev.Type, dev.Major, dev.Minor, dev.Access)
+ }
+ }
+
+ BlockAccessToKernelFilesystems(s.Privileged, s.PidNS.IsHost(), s.Mask, s.Unmask, &g)
+
+ g.ClearProcessEnv()
+ for name, val := range s.Env {
+ g.AddProcessEnv(name, val)
+ }
+
+ addRlimits(s, &g)
+
+ // NAMESPACES
+ if err := specConfigureNamespaces(s, &g, rt, pod); err != nil {
+ return nil, err
+ }
+ configSpec := g.Config
+
+ if err := securityConfigureGenerator(s, &g, newImage, rtc); err != nil {
+ return nil, err
+ }
+
+ // BIND MOUNTS
+ configSpec.Mounts = SupersedeUserMounts(mounts, configSpec.Mounts)
+ // Process mounts to ensure correct options
+ if err := InitFSMounts(configSpec.Mounts); err != nil {
+ return nil, err
+ }
+
+ // Add annotations
+ if configSpec.Annotations == nil {
+ configSpec.Annotations = make(map[string]string)
+ }
+
+ if s.Remove {
+ configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseTrue
+ } else {
+ configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseFalse
+ }
+
+ if len(s.VolumesFrom) > 0 {
+ configSpec.Annotations[define.InspectAnnotationVolumesFrom] = strings.Join(s.VolumesFrom, ",")
+ }
+
+ if s.Privileged {
+ configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseTrue
+ } else {
+ configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseFalse
+ }
+
+ if s.Init {
+ configSpec.Annotations[define.InspectAnnotationInit] = define.InspectResponseTrue
+ } else {
+ configSpec.Annotations[define.InspectAnnotationInit] = define.InspectResponseFalse
+ }
+
+ if s.OOMScoreAdj != nil {
+ g.SetProcessOOMScoreAdj(*s.OOMScoreAdj)
+ }
+ setProcOpts(s, &g)
+
+ return configSpec, nil
+}
+
+func WeightDevices(wtDevices map[string]spec.LinuxWeightDevice) ([]spec.LinuxWeightDevice, error) {
+ devs := []spec.LinuxWeightDevice{}
+ for k, v := range wtDevices {
+ statT := unix.Stat_t{}
+ if err := unix.Stat(k, &statT); err != nil {
+ return nil, fmt.Errorf("failed to inspect '%s' in --blkio-weight-device: %w", k, err)
+ }
+ dev := new(spec.LinuxWeightDevice)
+ dev.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
+ dev.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
+ dev.Weight = v.Weight
+ devs = append(devs, *dev)
+ }
+ return devs, nil
+}
diff --git a/pkg/specgen/generate/oci_unsupported.go b/pkg/specgen/generate/oci_unsupported.go
new file mode 100644
index 000000000..7e1b8c42c
--- /dev/null
+++ b/pkg/specgen/generate/oci_unsupported.go
@@ -0,0 +1,24 @@
+//go:build !linux && !freebsd
+// +build !linux,!freebsd
+
+package generate
+
+import (
+ "context"
+ "errors"
+
+ "github.com/containers/common/libimage"
+ "github.com/containers/common/pkg/config"
+ "github.com/containers/podman/v4/libpod"
+ "github.com/containers/podman/v4/pkg/specgen"
+ spec "github.com/opencontainers/runtime-spec/specs-go"
+)
+
+// SpecGenToOCI returns the base configuration for the container.
+func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, newImage *libimage.Image, mounts []spec.Mount, pod *libpod.Pod, finalCmd []string, compatibleOptions *libpod.InfraInherit) (*spec.Spec, error) {
+ return nil, errors.New("unsupported SpecGenToOCI")
+}
+
+func WeightDevices(wtDevices map[string]spec.LinuxWeightDevice) ([]spec.LinuxWeightDevice, error) {
+ return []spec.LinuxWeightDevice{}, errors.New("unsupported WeightDevices")
+}
diff --git a/pkg/specgen/generate/security_freebsd.go b/pkg/specgen/generate/security_freebsd.go
new file mode 100644
index 000000000..5fd66c769
--- /dev/null
+++ b/pkg/specgen/generate/security_freebsd.go
@@ -0,0 +1,19 @@
+package generate
+
+import (
+ "github.com/containers/common/libimage"
+ "github.com/containers/common/pkg/config"
+ "github.com/containers/podman/v4/libpod"
+ "github.com/containers/podman/v4/pkg/specgen"
+ "github.com/opencontainers/runtime-tools/generate"
+)
+
+// setLabelOpts sets the label options of the SecurityConfig according to the
+// input.
+func setLabelOpts(s *specgen.SpecGenerator, runtime *libpod.Runtime, pidConfig specgen.Namespace, ipcConfig specgen.Namespace) error {
+ return nil
+}
+
+func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, newImage *libimage.Image, rtc *config.Config) error {
+ return nil
+}
diff --git a/pkg/specgen/generate/security.go b/pkg/specgen/generate/security_linux.go
index aacefcbac..aacefcbac 100644
--- a/pkg/specgen/generate/security.go
+++ b/pkg/specgen/generate/security_linux.go
diff --git a/pkg/specgen/generate/security_unsupported.go b/pkg/specgen/generate/security_unsupported.go
new file mode 100644
index 000000000..d0f937e44
--- /dev/null
+++ b/pkg/specgen/generate/security_unsupported.go
@@ -0,0 +1,24 @@
+//go:build !linux && !freebsd
+// +build !linux,!freebsd
+
+package generate
+
+import (
+ "errors"
+
+ "github.com/containers/common/libimage"
+ "github.com/containers/common/pkg/config"
+ "github.com/containers/podman/v4/libpod"
+ "github.com/containers/podman/v4/pkg/specgen"
+ "github.com/opencontainers/runtime-tools/generate"
+)
+
+// setLabelOpts sets the label options of the SecurityConfig according to the
+// input.
+func setLabelOpts(s *specgen.SpecGenerator, runtime *libpod.Runtime, pidConfig specgen.Namespace, ipcConfig specgen.Namespace) error {
+ return errors.New("unsupported setLabelOpts")
+}
+
+func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, newImage *libimage.Image, rtc *config.Config) error {
+ return errors.New("unsupported securityConfigureGenerator")
+}
diff --git a/pkg/specgen/namespaces.go b/pkg/specgen/namespaces.go
index 03a2049f6..8cc0fe6a9 100644
--- a/pkg/specgen/namespaces.go
+++ b/pkg/specgen/namespaces.go
@@ -11,6 +11,7 @@ import (
"github.com/containers/common/pkg/cgroups"
cutil "github.com/containers/common/pkg/util"
"github.com/containers/podman/v4/libpod/define"
+ "github.com/containers/podman/v4/pkg/namespaces"
"github.com/containers/podman/v4/pkg/util"
"github.com/containers/storage"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -308,6 +309,14 @@ func ParseUserNamespace(ns string) (Namespace, error) {
case ns == "keep-id":
toReturn.NSMode = KeepID
return toReturn, nil
+ case strings.HasPrefix(ns, "keep-id:"):
+ split := strings.SplitN(ns, ":", 2)
+ if len(split) != 2 {
+ return toReturn, errors.New("invalid setting for keep-id: mode")
+ }
+ toReturn.NSMode = KeepID
+ toReturn.Value = split[1]
+ return toReturn, nil
case ns == "nomap":
toReturn.NSMode = NoMap
return toReturn, nil
@@ -490,7 +499,11 @@ func SetupUserNS(idmappings *storage.IDMappingOptions, userns Namespace, g *gene
return user, err
}
case KeepID:
- mappings, uid, gid, err := util.GetKeepIDMapping()
+ opts, err := namespaces.UsernsMode(userns.String()).GetKeepIDOptions()
+ if err != nil {
+ return user, err
+ }
+ mappings, uid, gid, err := util.GetKeepIDMapping(opts)
if err != nil {
return user, err
}
diff --git a/pkg/specgen/volumes.go b/pkg/specgen/volumes.go
index 84de4fdd1..e70ed5b13 100644
--- a/pkg/specgen/volumes.go
+++ b/pkg/specgen/volumes.go
@@ -23,6 +23,9 @@ type NamedVolume struct {
Dest string
// Options are options that the named volume will be mounted with.
Options []string
+ // IsAnonymous sets the named volume as anonymous even if it has a name
+ // This is used for emptyDir volumes from a kube yaml
+ IsAnonymous bool
}
// OverlayVolume holds information about a overlay volume that will be mounted into
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index 33c11d611..87e403986 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -342,7 +342,7 @@ func ParseSignal(rawSignal string) (syscall.Signal, error) {
}
// GetKeepIDMapping returns the mappings and the user to use when keep-id is used
-func GetKeepIDMapping() (*stypes.IDMappingOptions, int, int, error) {
+func GetKeepIDMapping(opts *namespaces.KeepIDUserNsOptions) (*stypes.IDMappingOptions, int, int, error) {
if !rootless.IsRootless() {
return nil, -1, -1, errors.New("keep-id is only supported in rootless mode")
}
@@ -359,6 +359,12 @@ func GetKeepIDMapping() (*stypes.IDMappingOptions, int, int, error) {
uid := rootless.GetRootlessUID()
gid := rootless.GetRootlessGID()
+ if opts.UID != nil {
+ uid = int(*opts.UID)
+ }
+ if opts.GID != nil {
+ gid = int(*opts.GID)
+ }
uids, gids, err := rootless.GetConfiguredMappings()
if err != nil {
diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go
index 7d3a2224c..d1eb960cd 100644
--- a/test/e2e/play_kube_test.go
+++ b/test/e2e/play_kube_test.go
@@ -509,6 +509,9 @@ spec:
volumes:
{{ range . }}
- name: {{ .Name }}
+ {{- if (eq .VolumeType "EmptyDir") }}
+ emptyDir: {}
+ {{- end }}
{{- if (eq .VolumeType "HostPath") }}
hostPath:
path: {{ .HostPath.Path }}
@@ -1242,12 +1245,15 @@ type ConfigMap struct {
Optional bool
}
+type EmptyDir struct{}
+
type Volume struct {
VolumeType string
Name string
HostPath
PersistentVolumeClaim
ConfigMap
+ EmptyDir
}
// getHostPathVolume takes a type and a location for a HostPath
@@ -1289,6 +1295,14 @@ func getConfigMapVolume(vName string, items []map[string]string, optional bool)
}
}
+func getEmptyDirVolume() *Volume {
+ return &Volume{
+ VolumeType: "EmptyDir",
+ Name: defaultVolName,
+ EmptyDir: EmptyDir{},
+ }
+}
+
type Env struct {
Name string
Value string
@@ -2762,6 +2776,43 @@ VOLUME %s`, ALPINE, hostPathDir+"/")
Expect(kube).Should(Exit(0))
})
+ It("podman play kube with emptyDir volume", func() {
+ podName := "test-pod"
+ ctrName1 := "vol-test-ctr"
+ ctrName2 := "vol-test-ctr-2"
+ ctr1 := getCtr(withVolumeMount("/test-emptydir", false), withImage(BB), withName(ctrName1))
+ ctr2 := getCtr(withVolumeMount("/test-emptydir-2", false), withImage(BB), withName(ctrName2))
+ pod := getPod(withPodName(podName), withVolume(getEmptyDirVolume()), withCtr(ctr1), withCtr(ctr2))
+ err = generateKubeYaml("pod", pod, kubeYaml)
+ Expect(err).To(BeNil())
+
+ kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube).Should(Exit(0))
+
+ emptyDirCheck1 := podmanTest.Podman([]string{"exec", podName + "-" + ctrName1, "ls", "/test-emptydir"})
+ emptyDirCheck1.WaitWithDefaultTimeout()
+ Expect(emptyDirCheck1).Should(Exit(0))
+
+ emptyDirCheck2 := podmanTest.Podman([]string{"exec", podName + "-" + ctrName2, "ls", "/test-emptydir-2"})
+ emptyDirCheck2.WaitWithDefaultTimeout()
+ Expect(emptyDirCheck2).Should(Exit(0))
+
+ volList1 := podmanTest.Podman([]string{"volume", "ls", "-q"})
+ volList1.WaitWithDefaultTimeout()
+ Expect(volList1).Should(Exit(0))
+ Expect(volList1.OutputToString()).To(Equal(defaultVolName))
+
+ remove := podmanTest.Podman([]string{"pod", "rm", "-f", podName})
+ remove.WaitWithDefaultTimeout()
+ Expect(remove).Should(Exit(0))
+
+ volList2 := podmanTest.Podman([]string{"volume", "ls", "-q"})
+ volList2.WaitWithDefaultTimeout()
+ Expect(volList2).Should(Exit(0))
+ Expect(volList2.OutputToString()).To(Equal(""))
+ })
+
It("podman play kube applies labels to pods", func() {
var numReplicas int32 = 5
expectedLabelKey := "key1"
diff --git a/test/e2e/run_userns_test.go b/test/e2e/run_userns_test.go
index 62e512d3a..016f67bf6 100644
--- a/test/e2e/run_userns_test.go
+++ b/test/e2e/run_userns_test.go
@@ -113,6 +113,16 @@ var _ = Describe("Podman UserNS support", func() {
Expect(session).Should(Exit(0))
uid := fmt.Sprintf("%d", os.Geteuid())
Expect(session.OutputToString()).To(ContainSubstring(uid))
+
+ session = podmanTest.Podman([]string{"run", "--userns=keep-id:uid=10,gid=12", "alpine", "sh", "-c", "echo $(id -u):$(id -g)"})
+ session.WaitWithDefaultTimeout()
+ if os.Geteuid() == 0 {
+ Expect(session).Should(Exit(125))
+ return
+ }
+
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(ContainSubstring("10:12"))
})
It("podman --userns=keep-id check passwd", func() {
diff --git a/test/system/090-events.bats b/test/system/090-events.bats
index ceb53ae73..cee0e23b0 100644
--- a/test/system/090-events.bats
+++ b/test/system/090-events.bats
@@ -64,7 +64,7 @@ load helpers
run_podman --events-backend=file tag $IMAGE $tag
run_podman --events-backend=file untag $IMAGE $tag
run_podman --events-backend=file tag $IMAGE $tag
- run_podman --events-backend=file rmi $tag
+ run_podman --events-backend=file rmi -f $imageID
run_podman --events-backend=file events --stream=false --filter type=image --since $t0
is "$output" ".*image push $imageID dir:$pushedDir
@@ -74,7 +74,8 @@ load helpers
.*image tag $imageID $tag
.*image untag $imageID $tag:latest
.*image tag $imageID $tag
-.*image remove $imageID $tag.*" \
+.*image untag $imageID $tag:latest
+.*image remove $imageID $imageID" \
"podman events"
}
diff --git a/vendor/github.com/containers/common/libimage/image.go b/vendor/github.com/containers/common/libimage/image.go
index d1548eb23..3cc843ed3 100644
--- a/vendor/github.com/containers/common/libimage/image.go
+++ b/vendor/github.com/containers/common/libimage/image.go
@@ -475,7 +475,11 @@ func (i *Image) removeRecursive(ctx context.Context, rmMap map[string]*RemoveIma
}
return processedIDs, err
}
+
report.Untagged = append(report.Untagged, i.Names()...)
+ for _, name := range i.Names() {
+ i.runtime.writeEvent(&Event{ID: i.ID(), Name: name, Time: time.Now(), Type: EventTypeImageUntag})
+ }
if !hasChildren {
report.Removed = true
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 5aa5af553..d80f64177 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -114,7 +114,7 @@ github.com/containers/buildah/pkg/rusage
github.com/containers/buildah/pkg/sshagent
github.com/containers/buildah/pkg/util
github.com/containers/buildah/util
-# github.com/containers/common v0.49.2-0.20220823130605-72a7da3358ac
+# github.com/containers/common v0.49.2-0.20220826180622-c2dcb4e70340
## explicit
github.com/containers/common/libimage
github.com/containers/common/libimage/define