summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com>2021-11-12 19:37:46 +0100
committerGitHub <noreply@github.com>2021-11-12 19:37:46 +0100
commit4808a63e5f1ad72d754c61c005c2c7c29ce48014 (patch)
tree3cfdd9e9f89024798a1bcd26dd56d4c7140d923d
parentfd010adfdcb6f578623b77281f2ae012bcd1ac85 (diff)
parent7c98d542b4c5ab0495f66a9179ae886e86cad273 (diff)
downloadpodman-4808a63e5f1ad72d754c61c005c2c7c29ce48014.tar.gz
podman-4808a63e5f1ad72d754c61c005c2c7c29ce48014.tar.bz2
podman-4808a63e5f1ad72d754c61c005c2c7c29ce48014.zip
Merge pull request #12274 from mheon/bump_342
Bump to v3.4.2
-rw-r--r--Makefile9
-rw-r--r--RELEASE_NOTES.md25
-rw-r--r--cmd/podman/common/create.go2
-rw-r--r--cmd/podman/containers/start.go3
-rw-r--r--cmd/podman/images/pull.go2
-rw-r--r--cmd/podman/images/scp.go2
-rw-r--r--cmd/podman/system/version.go2
-rw-r--r--contrib/cirrus/lib.sh25
-rwxr-xr-xcontrib/cirrus/pr-should-include-tests8
-rw-r--r--contrib/podmanimage/stable/Dockerfile9
-rw-r--r--contrib/podmanimage/testing/Dockerfile9
-rw-r--r--contrib/podmanimage/upstream/Dockerfile9
-rw-r--r--contrib/spec/podman.spec.in2
-rw-r--r--contrib/systemd/system/podman-restart.service3
-rw-r--r--docs/source/markdown/podman-build.1.md10
-rw-r--r--docs/source/markdown/podman-completion.1.md2
-rw-r--r--docs/source/markdown/podman-create.1.md11
-rw-r--r--docs/source/markdown/podman-generate-kube.1.md56
-rw-r--r--docs/source/markdown/podman-machine-init.1.md4
-rw-r--r--docs/source/markdown/podman-machine-ssh.1.md2
-rw-r--r--docs/source/markdown/podman-pause.1.md2
-rw-r--r--docs/source/markdown/podman-pod-rm.1.md2
-rw-r--r--docs/source/markdown/podman-run.1.md11
-rw-r--r--docs/source/markdown/podman.1.md2
-rw-r--r--go.mod2
-rw-r--r--go.sum4
-rw-r--r--libpod/container_internal.go26
-rw-r--r--libpod/container_internal_linux.go1
-rw-r--r--libpod/container_log_linux.go46
-rw-r--r--libpod/info.go2
-rw-r--r--libpod/kube.go142
-rw-r--r--libpod/lock/shm/shm_lock.go11
-rw-r--r--libpod/network/cni/cni_types.go2
-rw-r--r--libpod/network/cni/run.go6
-rw-r--r--libpod/networking_slirp4netns.go39
-rw-r--r--libpod/runtime.go2
-rw-r--r--libpod/runtime_ctr.go9
-rw-r--r--libpod/runtime_pod_linux.go52
-rw-r--r--nix/default-arm64.nix3
-rw-r--r--nix/default.nix3
-rw-r--r--pkg/api/handlers/compat/images_build.go15
-rw-r--r--pkg/api/server/handler_rid.go9
-rw-r--r--pkg/api/server/register_images.go4
-rw-r--r--pkg/api/server/swagger.go14
-rw-r--r--pkg/bindings/connection.go5
-rw-r--r--pkg/bindings/containers/attach.go4
-rw-r--r--pkg/bindings/containers/logs.go2
-rw-r--r--pkg/bindings/errors.go29
-rw-r--r--pkg/bindings/pods/pods.go14
-rw-r--r--pkg/bindings/test/common_test.go17
-rw-r--r--pkg/bindings/test/containers_test.go7
-rw-r--r--pkg/bindings/test/pods_test.go26
-rw-r--r--pkg/cgroups/cgroups.go4
-rw-r--r--pkg/domain/entities/images.go1
-rw-r--r--pkg/domain/infra/abi/generate.go3
-rw-r--r--pkg/domain/infra/tunnel/containers.go2
-rw-r--r--pkg/domain/infra/tunnel/images.go2
-rw-r--r--pkg/domain/infra/tunnel/network.go2
-rw-r--r--pkg/domain/infra/tunnel/secrets.go4
-rw-r--r--pkg/domain/infra/tunnel/volumes.go2
-rw-r--r--pkg/errorhandling/errorhandling.go14
-rw-r--r--pkg/machine/ignition.go18
-rw-r--r--pkg/specgenutil/specgen.go12
-rw-r--r--pkg/systemd/dbus.go2
-rw-r--r--test/e2e/common_test.go2
-rw-r--r--test/e2e/generate_kube_test.go9
-rw-r--r--test/e2e/libpod_suite_remote_test.go16
-rw-r--r--test/e2e/libpod_suite_test.go14
-rw-r--r--test/e2e/logs_test.go69
-rw-r--r--test/e2e/pod_rm_test.go17
-rw-r--r--test/e2e/run_networking_test.go20
-rw-r--r--test/e2e/run_test.go4
-rw-r--r--test/e2e/system_reset_test.go2
-rw-r--r--test/e2e/systemd_test.go17
-rw-r--r--test/e2e/trust_test.go63
-rw-r--r--test/e2e/version_test.go10
-rw-r--r--test/system/015-help.bats6
-rw-r--r--test/system/030-run.bats5
-rw-r--r--test/system/045-start.bats4
-rw-r--r--test/system/500-networking.bats7
-rw-r--r--test/upgrade/test-upgrade.bats16
-rw-r--r--test/utils/podmantest_test.go2
-rw-r--r--test/utils/utils.go16
-rw-r--r--troubleshooting.md4
-rw-r--r--utils/utils.go20
-rw-r--r--vendor/github.com/godbus/dbus/v5/auth.go2
-rw-r--r--vendor/github.com/godbus/dbus/v5/conn.go22
-rw-r--r--vendor/github.com/godbus/dbus/v5/message.go4
-rw-r--r--vendor/github.com/godbus/dbus/v5/transport_unixcred_netbsd.go14
-rw-r--r--vendor/modules.txt2
-rw-r--r--version/version.go2
91 files changed, 842 insertions, 301 deletions
diff --git a/Makefile b/Makefile
index cf796ed3c..d63cb4549 100644
--- a/Makefile
+++ b/Makefile
@@ -59,10 +59,11 @@ PKG_MANAGER ?= $(shell command -v dnf yum|head -n1)
PRE_COMMIT = $(shell command -v bin/venv/bin/pre-commit ~/.local/bin/pre-commit pre-commit | head -n1)
# This isn't what we actually build; it's a superset, used for target
-# dependencies. Basically: all *.go files, except *_test.go, and except
-# anything in a dot subdirectory. If any of these files is newer than
-# our target (bin/podman{,-remote}), a rebuild is triggered.
-SOURCES = $(shell find . -path './.*' -prune -o \( -name '*.go' -a ! -name '*_test.go' \) -print)
+# dependencies. Basically: all *.go and *.c files, except *_test.go,
+# and except anything in a dot subdirectory. If any of these files is
+# newer than our target (bin/podman{,-remote}), a rebuild is
+# triggered.
+SOURCES = $(shell find . -path './.*' -prune -o \( \( -name '*.go' -o -name '*.c' \) -a ! -name '*_test.go' \) -print)
BUILDFLAGS := -mod=vendor $(BUILDFLAGS)
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index cca300f07..110de4376 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,24 @@
# Release Notes
+## 3.4.2
+### Bugfixes
+- Fixed a bug where `podman tag` could not tag manifest lists ([#12046](https://github.com/containers/podman/issues/12046)).
+- Fixed a bug where built-in volumes specified by images would not be created correctly under some circumstances.
+- Fixed a bug where, when using Podman Machine on OS X, containers in pods did not have working port forwarding from the host ([#12207](https://github.com/containers/podman/issues/12207)).
+- Fixed a bug where the `podman network reload` command command on containers using the `slirp4netns` network mode and the `rootlessport` port forwarding driver would make an unnecessary attempt to restart `rootlessport` on containers that did not forward ports.
+- Fixed a bug where the `podman generate kube` command would generate YAML including some unnecessary (set to default) fields (e.g. empty SELinux and DNS configuration blocks, and the `privileged` flag when set to false) ([#11995](https://github.com/containers/podman/issues/11995)).
+- Fixed a bug where the `podman pod rm` command could, if interrupted at the right moment, leave a reference to an already-removed infra container behind ([#12034](https://github.com/containers/podman/issues/12034)).
+- Fixed a bug where the `podman pod rm` command would not remove pods with more than one container if all containers save for the infra container were stopped unless `--force` was specified ([#11713](https://github.com/containers/podman/issues/11713)).
+- Fixed a bug where the `--memory` flag to `podman run` and `podman create` did not accept a limit of 0 (which should specify unlimited memory) ([#12002](https://github.com/containers/podman/issues/12002)).
+- Fixed a bug where the remote Podman client's `podman build` command could attempt to build a Dockerfile in the working directory of the `podman system service` instance instead of the Dockerfile specified by the user ([#12054](https://github.com/containers/podman/issues/12054)).
+- Fixed a bug where the `podman logs --tail` command could function improperly (printing more output than requested) when the `journald` log driver was used.
+- Fixed a bug where containers run using the `slirp4netns` network mode with IPv6 enabled would not have IPv6 connectivity until several seconds after they started ([#11062](https://github.com/containers/podman/issues/11062)).
+- Fixed a bug where some Podman commands could cause an extra `dbus-daemon` process to be created ([#9727](https://github.com/containers/podman/issues/9727)).
+- Fixed a bug where rootless Podman would sometimes print warnings about a failure to move the pause process into a given CGroup ([#12065](https://github.com/containers/podman/issues/12065)).
+- Fixed a bug where the `checkpointed` field in `podman inspect` on a container was not set to false after a container was restored.
+- Fixed a bug where the `podman system service` command would print overly-verbose logs about request IDs ([#12181](https://github.com/containers/podman/issues/12181)).
+- Fixed a bug where Podman could, when creating a new container without a name explicitly specified by the user, sometimes use an auto-generated name already in use by another container if multiple containers were being created in parallel ([#11735](https://github.com/containers/podman/issues/11735)).
+
## 3.4.1
### Bugfixes
- Fixed a bug where `podman machine init` could, under some circumstances, create invalid machine configurations which could not be started ([#11824](https://github.com/containers/podman/issues/11824)).
@@ -133,7 +152,7 @@
### Features
- Containers inside VMs created by `podman machine` will now automatically handle port forwarding - containers in `podman machine` VMs that publish ports via `--publish` or `--publish-all` will have these ports not just forwarded on the VM, but also on the host system.
- The `podman play kube` command's `--network` option now accepts advanced network options (e.g. `--network slirp4netns:port_handler=slirp4netns`) ([#10807](https://github.com/containers/podman/issues/10807)).
-- The `podman play kube` commmand now supports Kubernetes liveness probes, which will be created as Podman healthchecks.
+- The `podman play kube` command now supports Kubernetes liveness probes, which will be created as Podman healthchecks.
- Podman now provides a systemd unit, `podman-restart.service`, which, when enabled, will restart all containers that were started with `--restart=always` after the system reboots.
- Rootless Podman can now be configured to use CNI networking by default by using the `rootless_networking` option in `containers.conf`.
- Images can now be pulled using `image:tag@digest` syntax (e.g. `podman pull fedora:34@sha256:1b0d4ddd99b1a8c8a80e885aafe6034c95f266da44ead992aab388e6aa91611a`) ([#6721](https://github.com/containers/podman/issues/6721)).
@@ -389,7 +408,7 @@
- Fixed a bug where images with empty layers were stored incorrectly, causing them to be unable to be pushed or saved.
- Fixed a bug where the `podman rmi` command could fail to remove corrupt images from storage.
- Fixed a bug where the remote Podman client's `podman save` command did not support the `oci-dir` and `docker-dir` formats ([#9742](https://github.com/containers/podman/issues/9742)).
-- Fixed a bug where volume mounts from `podman play kube` created with a trailing `/` in the container path were were not properly superceding named volumes from the image ([#9618](https://github.com/containers/podman/issues/9618)).
+- Fixed a bug where volume mounts from `podman play kube` created with a trailing `/` in the container path were were not properly superseding named volumes from the image ([#9618](https://github.com/containers/podman/issues/9618)).
- Fixed a bug where Podman could fail to build on 32-bit architectures.
### Misc
@@ -1034,7 +1053,7 @@
## 2.0.5
### Features
- Rootless Podman will now add an entry to `/etc/passwd` for the user who ran Podman if run with `--userns=keep-id`.
-- The `podman system connection` command has been reworked to support multiple connections, and reenabled for use!
+- The `podman system connection` command has been reworked to support multiple connections, and re-enabled for use!
- Podman now has a new global flag, `--connection`, to specify a connection to a remote Podman API instance.
### Changes
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go
index b3dfc4967..643f6728a 100644
--- a/cmd/podman/common/create.go
+++ b/cmd/podman/common/create.go
@@ -426,7 +426,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
createFlags.StringVar(
&cf.Variant,
variantFlagName, "",
- "Use _VARIANT_ instead of the running architecture variant for choosing images",
+ "Use `VARIANT` instead of the running architecture variant for choosing images",
)
_ = cmd.RegisterFlagCompletionFunc(variantFlagName, completion.AutocompleteNone)
diff --git a/cmd/podman/containers/start.go b/cmd/podman/containers/start.go
index 1163b9093..8813fc273 100644
--- a/cmd/podman/containers/start.go
+++ b/cmd/podman/containers/start.go
@@ -87,6 +87,9 @@ func validateStart(cmd *cobra.Command, args []string) error {
if len(args) == 0 && !startOptions.Latest && !startOptions.All {
return errors.New("start requires at least one argument")
}
+ if startOptions.All && startOptions.Latest {
+ return errors.Errorf("--all and --latest cannot be used together")
+ }
if len(args) > 0 && startOptions.Latest {
return errors.Errorf("--latest and containers cannot be used together")
}
diff --git a/cmd/podman/images/pull.go b/cmd/podman/images/pull.go
index a4e3515db..a990d1626 100644
--- a/cmd/podman/images/pull.go
+++ b/cmd/podman/images/pull.go
@@ -92,7 +92,7 @@ func pullFlags(cmd *cobra.Command) {
_ = cmd.RegisterFlagCompletionFunc(osFlagName, completion.AutocompleteOS)
variantFlagName := "variant"
- flags.StringVar(&pullOptions.Variant, variantFlagName, "", " use VARIANT instead of the running architecture variant for choosing images")
+ flags.StringVar(&pullOptions.Variant, variantFlagName, "", "Use VARIANT instead of the running architecture variant for choosing images")
_ = cmd.RegisterFlagCompletionFunc(variantFlagName, completion.AutocompleteNone)
platformFlagName := "platform"
diff --git a/cmd/podman/images/scp.go b/cmd/podman/images/scp.go
index 176563440..c89a090bf 100644
--- a/cmd/podman/images/scp.go
+++ b/cmd/podman/images/scp.go
@@ -185,7 +185,7 @@ func saveToRemote(image, localFile string, tag string, uri *urlP.URL, iden strin
return errors.Wrapf(define.ErrInvalidArg, "Renaming of an image is currently not supported")
}
podman := os.Args[0]
- run := podman + " image save " + image + " --format=oci-archive --output=" + remoteFile // run ssh image load of the file copied via scp. Files are reverse in thie case...
+ run := podman + " image save " + image + " --format=oci-archive --output=" + remoteFile // run ssh image load of the file copied via scp. Files are reverse in this case...
_, err = connection.ExecRemoteCommand(dial, run)
if err != nil {
return nil
diff --git a/cmd/podman/system/version.go b/cmd/podman/system/version.go
index 4502b156c..f71af8e72 100644
--- a/cmd/podman/system/version.go
+++ b/cmd/podman/system/version.go
@@ -20,7 +20,7 @@ var (
versionCommand = &cobra.Command{
Use: "version [options]",
Args: validate.NoArgs,
- Short: "Display the Podman Version Information",
+ Short: "Display the Podman version information",
RunE: version,
ValidArgsFunction: completion.AutocompleteNone,
}
diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh
index 9a7bfba8f..9b7c613f5 100644
--- a/contrib/cirrus/lib.sh
+++ b/contrib/cirrus/lib.sh
@@ -143,6 +143,8 @@ setup_rootless() {
local rootless_uid
local rootless_gid
local env_var_val
+ local akfilepath
+ local sshcmd
# Only do this once; established by setup_environment.sh
# shellcheck disable=SC2154
@@ -169,24 +171,25 @@ setup_rootless() {
ssh-keygen -P "" -f "$HOME/.ssh/id_rsa"
msg "Allowing ssh key for $ROOTLESS_USER"
+ akfilepath="/home/$ROOTLESS_USER/.ssh/authorized_keys"
(umask 077 && mkdir "/home/$ROOTLESS_USER/.ssh")
chown -R $ROOTLESS_USER:$ROOTLESS_USER "/home/$ROOTLESS_USER/.ssh"
install -o $ROOTLESS_USER -g $ROOTLESS_USER -m 0600 \
- "$HOME/.ssh/id_rsa.pub" "/home/$ROOTLESS_USER/.ssh/authorized_keys"
+ "$HOME/.ssh/id_rsa.pub" "$akfilepath"
# Makes debugging easier
- cat /root/.ssh/authorized_keys >> "/home/$ROOTLESS_USER/.ssh/authorized_keys"
-
- msg "Configuring subuid and subgid"
- grep -q "${ROOTLESS_USER}" /etc/subuid || \
- echo "${ROOTLESS_USER}:$[rootless_uid * 100]:65536" | \
- tee -a /etc/subuid >> /etc/subgid
+ cat /root/.ssh/authorized_keys >> "$akfilepath"
msg "Ensure the ssh daemon is up and running within 5 minutes"
systemctl start sshd
- lilto ssh $ROOTLESS_USER@localhost \
- -o UserKnownHostsFile=/dev/null \
- -o StrictHostKeyChecking=no \
- -o CheckHostIP=no true
+ sshcmd="ssh $ROOTLESS_USER@localhost
+ -o UserKnownHostsFile=/dev/null
+ -o StrictHostKeyChecking=no
+ -o CheckHostIP=no"
+ lilto $sshcmd true # retry until sshd is up
+
+ msg "Configuring rootless user self-access to ssh to localhost"
+ $sshcmd ssh-keygen -P '""' -f "/home/$ROOTLESS_USER/.ssh/id_rsa"
+ cat "/home/$ROOTLESS_USER/.ssh/id_rsa" >> "$akfilepath"
}
install_test_configs() {
diff --git a/contrib/cirrus/pr-should-include-tests b/contrib/cirrus/pr-should-include-tests
index 4b6329311..8103df41d 100755
--- a/contrib/cirrus/pr-should-include-tests
+++ b/contrib/cirrus/pr-should-include-tests
@@ -12,9 +12,6 @@ fi
if [[ "${CIRRUS_CHANGE_MESSAGE}" =~ NO.NEW.TESTS.NEEDED ]]; then
exit 0
fi
-if [[ "${CIRRUS_CHANGE_MESSAGE}" =~ NO.TESTS.NEEDED ]]; then
- exit 0
-fi
# HEAD should be good enough, but the CIRRUS envariable allows us to test
head=${CIRRUS_CHANGE_IN_REPO:-HEAD}
@@ -52,14 +49,11 @@ if [[ -z "$filtered_changes" ]]; then
exit 0
fi
-# One last chance: perhaps the developer included the magic '[NO (NEW) TESTS NEEDED]'
+# One last chance: perhaps the developer included the magic '[NO NEW TESTS NEEDED]'
# string in an amended commit.
if git log --format=%B ${base}..${head} | fgrep '[NO NEW TESTS NEEDED]'; then
exit 0
fi
-if git log --format=%B ${base}..${head} | fgrep '[NO TESTS NEEDED]'; then
- exit 0
-fi
cat <<EOF
$(basename $0): PR does not include changes in the 'tests' directory
diff --git a/contrib/podmanimage/stable/Dockerfile b/contrib/podmanimage/stable/Dockerfile
index f980d15ed..7950269d2 100644
--- a/contrib/podmanimage/stable/Dockerfile
+++ b/contrib/podmanimage/stable/Dockerfile
@@ -19,14 +19,15 @@ RUN useradd podman; \
echo podman:10000:5000 > /etc/subuid; \
echo podman:10000:5000 > /etc/subgid;
-VOLUME /var/lib/containers
-VOLUME /home/podman/.local/share/containers
-RUN mkdir -p /home/podman/.local/share/containers
+RUN mkdir -p /home/podman/.local/share/containers; chown podman:podman -R /home/podman
ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/containers.conf /etc/containers/containers.conf
ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/podman-containers.conf /home/podman/.config/containers/containers.conf
-RUN chown podman:podman -R /home/podman
+# Note VOLUME options must always happen after the chown call above
+# RUN commands can not modify existing volumes
+VOLUME /var/lib/containers
+VOLUME /home/podman/.local/share/containers
# chmod containers.conf and adjust storage.conf to enable Fuse storage.
RUN chmod 644 /etc/containers/containers.conf; sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' /etc/containers/storage.conf
diff --git a/contrib/podmanimage/testing/Dockerfile b/contrib/podmanimage/testing/Dockerfile
index 58b11a20b..03da05806 100644
--- a/contrib/podmanimage/testing/Dockerfile
+++ b/contrib/podmanimage/testing/Dockerfile
@@ -19,14 +19,15 @@ RUN useradd podman; \
echo podman:10000:5000 > /etc/subuid; \
echo podman:10000:5000 > /etc/subgid;
-VOLUME /var/lib/containers
-VOLUME /home/podman/.local/share/containers
-RUN mkdir -p /home/podman/.local/share/containers
+RUN mkdir -p /home/podman/.local/share/containers; chown podman:podman -R /home/podman
ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/containers.conf /etc/containers/containers.conf
ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/podman-containers.conf /home/podman/.config/containers/containers.conf
-RUN chown podman:podman -R /home/podman
+# Note VOLUME options must always happen after the chown call above
+# RUN commands can not modify existing volumes
+VOLUME /var/lib/containers
+VOLUME /home/podman/.local/share/containers
# chmod containers.conf and adjust storage.conf to enable Fuse storage.
RUN chmod 644 /etc/containers/containers.conf; sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' /etc/containers/storage.conf
diff --git a/contrib/podmanimage/upstream/Dockerfile b/contrib/podmanimage/upstream/Dockerfile
index 75de947ea..89ec6e39b 100644
--- a/contrib/podmanimage/upstream/Dockerfile
+++ b/contrib/podmanimage/upstream/Dockerfile
@@ -68,14 +68,15 @@ RUN useradd podman; \
echo podman:10000:5000 > /etc/subuid; \
echo podman:10000:5000 > /etc/subgid;
-VOLUME /var/lib/containers
-VOLUME /home/podman/.local/share/containers
-RUN mkdir -p /home/podman/.local/share/containers
+RUN mkdir -p /home/podman/.local/share/containers; chown podman:podman -R /home/podman
ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/containers.conf /etc/containers/containers.conf
ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/podman-containers.conf /home/podman/.config/containers/containers.conf
-RUN chown podman:podman -R /home/podman
+# Note VOLUME options must always happen after the chown call above
+# RUN commands can not modify existing volumes
+VOLUME /var/lib/containers
+VOLUME /home/podman/.local/share/containers
# chmod containers.conf and adjust storage.conf to enable Fuse storage.
RUN chmod 644 /etc/containers/containers.conf; sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' /etc/containers/storage.conf
diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in
index 683797cd0..00f9ad6d0 100644
--- a/contrib/spec/podman.spec.in
+++ b/contrib/spec/podman.spec.in
@@ -36,7 +36,7 @@ Epoch: 99
%else
Epoch: 0
%endif
-Version: 3.4.2
+Version: 3.4.3
Release: #COMMITDATE#.git%{shortcommit0}%{?dist}
Summary: Manage Pods, Containers and Container Images
License: ASL 2.0
diff --git a/contrib/systemd/system/podman-restart.service b/contrib/systemd/system/podman-restart.service
index baf12b3ae..b8c1adca2 100644
--- a/contrib/systemd/system/podman-restart.service
+++ b/contrib/systemd/system/podman-restart.service
@@ -5,8 +5,9 @@ StartLimitIntervalSec=0
[Service]
Type=oneshot
+RemainAfterExit=true
Environment=LOGGING="--log-level=info"
ExecStart=/usr/bin/podman $LOGGING start --all --filter restart-policy=always
[Install]
-WantedBy=multi-user.target
+WantedBy=multi-user.target default.target
diff --git a/docs/source/markdown/podman-build.1.md b/docs/source/markdown/podman-build.1.md
index 0f52ad592..965f5319f 100644
--- a/docs/source/markdown/podman-build.1.md
+++ b/docs/source/markdown/podman-build.1.md
@@ -631,7 +631,7 @@ Sets the configuration for user namespaces when handling `RUN` instructions.
The configured value can be "" (the empty string) or "container" to indicate
that a new user namespace should be created, it can be "host" to indicate that
the user namespace in which `podman` itself is being run should be reused, or
-it can be the path to an user namespace which is already in use by another
+it can be the path to a user namespace which is already in use by another
process.
#### **--userns-uid-map**=*mapping*
@@ -774,6 +774,14 @@ content label. Shared volume labels allow all containers to read/write content.
The `Z` option tells Podman to label the content with a private unshared label.
Only the current container can use a private volume.
+Note: Do not relabel system files and directories. Relabeling system content
+might cause other confined services on your machine to fail. For these types
+of containers, disabling SELinux separation is recommended. The option
+`--security-opt label=disable` disables SELinux separation for the container.
+For example, if a user wanted to volume mount their entire home directory into the build containers, they need to disable SELinux separation.
+
+ $ podman build --security-opt label=disable -v $HOME:/home/user .
+
`Overlay Volume Mounts`
The `:O` flag tells Podman to mount the directory from the host as a
diff --git a/docs/source/markdown/podman-completion.1.md b/docs/source/markdown/podman-completion.1.md
index 639332365..41f504363 100644
--- a/docs/source/markdown/podman-completion.1.md
+++ b/docs/source/markdown/podman-completion.1.md
@@ -40,7 +40,7 @@ Shell completion needs to be already enabled in the environment. The following c
**echo "autoload -U compinit; compinit" >> ~/.zshrc**
To make it available for all zsh sessions run:\
-**podman completion -f "${fpath[1]}/_podman zsh"**
+**podman completion -f "${fpath[1]}/_podman" zsh**
Once the shell is reloaded the auto-completion should be working.
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index 40439dacb..7cbb71d85 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -1231,6 +1231,15 @@ content label. Shared volume labels allow all containers to read/write content.
The `Z` option tells Podman to label the content with a private unshared label.
Only the current container can use a private volume.
+Note: Do not relabel system files and directories. Relabeling system content
+might cause other confined services on your machine to fail. For these types
+of containers we recommend that disable SELinux separation. The option
+`--security-opt label=disable` disables SELinux separation for containers used in the build.
+For example if a user wanted to volume mount their entire home directory into a
+container, they need to disable SELinux separation.
+
+ $ podman create --security-opt label=disable -v $HOME:/home/user fedora touch /home/user/file
+
`Overlay Volume Mounts`
The `:O` flag tells Podman to mount the directory from the host as a
@@ -1453,7 +1462,7 @@ Note: RHEL7 and Centos 7 will not have this feature until RHEL7.7 is released.
In order for users to run rootless, there must be an entry for their username in /etc/subuid and /etc/subgid which lists the UIDs for their user namespace.
Rootless Podman works better if the fuse-overlayfs and slirp4netns packages are installed.
-The fuse-overlay package provides a userspace overlay storage driver, otherwise users need to use
+The fuse-overlayfs package provides a userspace overlay storage driver, otherwise users need to use
the vfs storage driver, which is diskspace expensive and does not perform well. slirp4netns is
required for VPN, without it containers need to be run with the --network=host flag.
diff --git a/docs/source/markdown/podman-generate-kube.1.md b/docs/source/markdown/podman-generate-kube.1.md
index 9ae3941ec..a583afcf9 100644
--- a/docs/source/markdown/podman-generate-kube.1.md
+++ b/docs/source/markdown/podman-generate-kube.1.md
@@ -54,13 +54,7 @@ spec:
- docker-entrypoint.sh
- mysqld
env:
- - name: PATH
- value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- - name: TERM
- value: xterm
- name: HOSTNAME
- - name: container
- value: podman
- name: GOSU_VERSION
value: "1.10"
- name: GPG_KEYS
@@ -77,14 +71,14 @@ spec:
ports:
- containerPort: 3306
hostPort: 36533
- protocol: TCP
resources: {}
securityContext:
- allowPrivilegeEscalation: true
- privileged: false
- readOnlyRootFilesystem: false
+ capabilities:
+ drop:
+ - CAP_MKNOD
+ - CAP_NET_RAW
+ - CAP_AUDIT_WRITE
tty: true
- workingDir: /
status: {}
```
@@ -106,31 +100,18 @@ spec:
containers:
- command:
- /bin/sh
- env:
- - name: PATH
- value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- - name: TERM
- value: xterm
- - name: container
- value: podman
image: docker.io/library/alpine:latest
name: test-bind-mount
resources: {}
securityContext:
- allowPrivilegeEscalation: true
capabilities:
drop:
- CAP_MKNOD
- CAP_NET_RAW
- CAP_AUDIT_WRITE
- privileged: false
- readOnlyRootFilesystem: false
- seLinuxOptions: {}
volumeMounts:
- mountPath: /volume
name: home-user-my-data-host
- workingDir: /
- dnsConfig: {}
restartPolicy: Never
volumes:
- hostPath:
@@ -158,31 +139,18 @@ spec:
containers:
- command:
- /bin/sh
- env:
- - name: PATH
- value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- - name: TERM
- value: xterm
- - name: container
- value: podman
image: docker.io/library/alpine:latest
name: test-bind-mount
resources: {}
securityContext:
- allowPrivilegeEscalation: true
capabilities:
drop:
- CAP_MKNOD
- CAP_NET_RAW
- CAP_AUDIT_WRITE
- privileged: false
- readOnlyRootFilesystem: false
- seLinuxOptions: {}
volumeMounts:
- mountPath: /volume
name: priceless-data-pvc
- workingDir: /
- dnsConfig: {}
restartPolicy: Never
volumes:
- name: priceless-data-pvc
@@ -210,22 +178,9 @@ spec:
- command:
- python3
- /root/code/graph.py
- env:
- - name: PATH
- value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- - name: TERM
- value: xterm
- - name: HOSTNAME
- - name: container
- value: podman
image: quay.io/baude/demoweb:latest
name: practicalarchimedes
resources: {}
- securityContext:
- allowPrivilegeEscalation: true
- capabilities: {}
- privileged: false
- readOnlyRootFilesystem: false
tty: true
workingDir: /root/code
status: {}
@@ -242,7 +197,6 @@ spec:
- name: "8050"
nodePort: 31269
port: 8050
- protocol: TCP
targetPort: 0
selector:
app: demoweb
diff --git a/docs/source/markdown/podman-machine-init.1.md b/docs/source/markdown/podman-machine-init.1.md
index 8a65be5a9..8b26728d5 100644
--- a/docs/source/markdown/podman-machine-init.1.md
+++ b/docs/source/markdown/podman-machine-init.1.md
@@ -18,6 +18,10 @@ tied to the Linux kernel.
SSH keys are automatically generated to access the VM, and system connections to the root account
and a user account inside the VM are added.
+By default, the VM distribution is [Fedora CoreOS](https://getfedora.org/en/coreos?stream=testing).
+Fedora CoreOS upgrades come out every 14 days and are detected and installed automatically. The VM will be rebooted during the upgrade.
+For more information on updates and advanced configuration, please see the FCOS update docs [here](https://docs.fedoraproject.org/en-US/fedora-coreos/auto-updates/) and [here](https://coreos.github.io/zincati/usage/updates-strategy/).
+
## OPTIONS
#### **--cpus**=*number*
diff --git a/docs/source/markdown/podman-machine-ssh.1.md b/docs/source/markdown/podman-machine-ssh.1.md
index a5cf69107..24ae58607 100644
--- a/docs/source/markdown/podman-machine-ssh.1.md
+++ b/docs/source/markdown/podman-machine-ssh.1.md
@@ -9,7 +9,7 @@ podman\-machine\-ssh - SSH into a virtual machine
## DESCRIPTION
SSH into a Podman-managed virtual machine and optionally execute a command
-on the virtual machine. Unless using the default virtual machine, the
+on the virtual machine. Unless using the default virtual machine, the
first argument must be the virtual machine name. The optional command to
execute can then follow. If no command is provided, an interactive session
with the virtual machine is established.
diff --git a/docs/source/markdown/podman-pause.1.md b/docs/source/markdown/podman-pause.1.md
index 123362822..90ea1e32e 100644
--- a/docs/source/markdown/podman-pause.1.md
+++ b/docs/source/markdown/podman-pause.1.md
@@ -31,7 +31,7 @@ podman pause 860a4b23
Pause all **running** containers.
```
-podman stop -a
+podman pause -a
```
## SEE ALSO
diff --git a/docs/source/markdown/podman-pod-rm.1.md b/docs/source/markdown/podman-pod-rm.1.md
index d185385b6..ce91dab5b 100644
--- a/docs/source/markdown/podman-pod-rm.1.md
+++ b/docs/source/markdown/podman-pod-rm.1.md
@@ -7,7 +7,7 @@ podman\-pod\-rm - Remove one or more stopped pods and containers
**podman pod rm** [*options*] *pod*
## DESCRIPTION
-**podman pod rm** will remove one or more stopped pods and their containers from the host. The pod name or ID can be used. The \-f option stops all containers and then removes them before removing the pod.
+**podman pod rm** will remove one or more stopped pods and their containers from the host. The pod name or ID can be used. The \-f option stops all containers and then removes them before removing the pod. If all containers added by the user are in an exited state, the pod will be removed.
## OPTIONS
diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md
index c538935fd..811bc725b 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -1288,6 +1288,15 @@ share the volume content. As a result, Podman labels the content with a shared
content label. Shared volume labels allow all containers to read/write content.
The **Z** option tells Podman to label the content with a private unshared label.
+Note: Do not relabel system files and directories. Relabeling system content
+might cause other confined services on your machine to fail. For these types
+of containers we recommend that disable SELinux separation. The option
+`--security-opt label=disable` disables SELinux separation for the container.
+For example if a user wanted to volume mount their entire home directory into a
+container, they need to disable SELinux separation.
+
+ $ podman run --security-opt label=disable -v $HOME:/home/user fedora touch /home/user/file
+
`Overlay Volume Mounts`
The `:O` flag tells Podman to mount the directory from the host as a
@@ -1801,7 +1810,7 @@ Note: RHEL7 and Centos 7 will not have this feature until RHEL7.7 is released.
In order for users to run rootless, there must be an entry for their username in _/etc/subuid_ and _/etc/subgid_ which lists the UIDs for their user namespace.
Rootless Podman works better if the fuse-overlayfs and slirp4netns packages are installed.
-The **fuse-overlay** package provides a userspace overlay storage driver, otherwise users need to use
+The **fuse-overlayfs** package provides a userspace overlay storage driver, otherwise users need to use
the **vfs** storage driver, which is diskspace expensive and does not perform well. slirp4netns is
required for VPN, without it containers need to be run with the **--network=host** flag.
diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md
index 864ff34bc..49d40be0c 100644
--- a/docs/source/markdown/podman.1.md
+++ b/docs/source/markdown/podman.1.md
@@ -317,7 +317,7 @@ Podman can also be used as non-root user. When podman runs in rootless mode, a u
Containers created by a non-root user are not visible to other users and are not seen or managed by Podman running as root.
-It is required to have multiple uids/gids set for an user. Be sure the user is present in the files `/etc/subuid` and `/etc/subgid`.
+It is required to have multiple uids/gids set for a user. Be sure the user is present in the files `/etc/subuid` and `/etc/subgid`.
If you have a recent version of usermod, you can execute the following
commands to add the ranges to the files
diff --git a/go.mod b/go.mod
index bdad4c244..5808d70d7 100644
--- a/go.mod
+++ b/go.mod
@@ -32,7 +32,7 @@ require (
github.com/dtylman/scp v0.0.0-20181017070807-f3000a34aef4
github.com/fsnotify/fsnotify v1.5.1
github.com/ghodss/yaml v1.0.0
- github.com/godbus/dbus/v5 v5.0.5
+ github.com/godbus/dbus/v5 v5.0.6
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
github.com/google/uuid v1.3.0
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33
diff --git a/go.sum b/go.sum
index b9eed814f..952774d35 100644
--- a/go.sum
+++ b/go.sum
@@ -403,8 +403,8 @@ github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68Fp
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/godbus/dbus/v5 v5.0.5 h1:9Eg0XUhQxtkV8ykTMKtMMYY72g4NgxtRq4jgh4Ih5YM=
-github.com/godbus/dbus/v5 v5.0.5/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/godbus/dbus/v5 v5.0.6 h1:mkgN1ofwASrYnJ5W6U/BxG15eXXXjirgZc7CLqkcaro=
+github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 2ca49758d..54d6b1303 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -479,9 +479,27 @@ func (c *Container) setupStorage(ctx context.Context) error {
c.setupStorageMapping(&options.IDMappingOptions, &c.config.IDMappings)
- containerInfo, err := c.runtime.storageService.CreateContainerStorage(ctx, c.runtime.imageContext, c.config.RootfsImageName, c.config.RootfsImageID, c.config.Name, c.config.ID, options)
- if err != nil {
- return errors.Wrapf(err, "error creating container storage")
+ // Unless the user has specified a name, use a randomly generated one.
+ // Note that name conflicts may occur (see #11735), so we need to loop.
+ generateName := c.config.Name == ""
+ var containerInfo ContainerInfo
+ var containerInfoErr error
+ for {
+ if generateName {
+ name, err := c.runtime.generateName()
+ if err != nil {
+ return err
+ }
+ c.config.Name = name
+ }
+ containerInfo, containerInfoErr = c.runtime.storageService.CreateContainerStorage(ctx, c.runtime.imageContext, c.config.RootfsImageName, c.config.RootfsImageID, c.config.Name, c.config.ID, options)
+
+ if !generateName || errors.Cause(containerInfoErr) != storage.ErrDuplicateName {
+ break
+ }
+ }
+ if containerInfoErr != nil {
+ return errors.Wrapf(containerInfoErr, "error creating container storage")
}
c.config.IDMappings.UIDMap = containerInfo.UIDMap
@@ -2100,7 +2118,7 @@ func (c *Container) checkReadyForRemoval() error {
return errors.Wrapf(define.ErrCtrStateInvalid, "container %s is in invalid state", c.ID())
}
- if c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused) {
+ if c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused) && !c.IsInfra() {
return errors.Wrapf(define.ErrCtrStateInvalid, "cannot remove container %s as it is %s - running or paused containers cannot be removed without force", c.ID(), c.state.State.String())
}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 310110679..208e089b5 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -1483,6 +1483,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
logrus.Debugf("Restored container %s", c.ID())
c.state.State = define.ContainerStateRunning
+ c.state.Checkpointed = false
if !options.Keep {
// Delete all checkpoint related files. At this point, in theory, all files
diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go
index ca1e11ef5..b6b780bab 100644
--- a/libpod/container_log_linux.go
+++ b/libpod/container_log_linux.go
@@ -91,8 +91,12 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption
var cursorError error
for i := 1; i <= 3; i++ {
cursor, cursorError = journal.GetCursor()
+ hundreds := 1
+ for j := 1; j < i; j++ {
+ hundreds *= 2
+ }
if cursorError != nil {
- time.Sleep(time.Duration(i*100) * time.Millisecond)
+ time.Sleep(time.Duration(hundreds*100) * time.Millisecond)
continue
}
break
@@ -117,8 +121,26 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption
}()
tailQueue := []*logs.LogLine{} // needed for options.Tail
- doTail := options.Tail > 0
+ doTail := options.Tail >= 0
+ doTailFunc := func() {
+ // Flush *once* we hit the end of the journal.
+ startIndex := int64(len(tailQueue))
+ outputLines := int64(0)
+ for startIndex > 0 && outputLines < options.Tail {
+ startIndex--
+ for startIndex > 0 && tailQueue[startIndex].Partial() {
+ startIndex--
+ }
+ outputLines++
+ }
+ for i := startIndex; i < int64(len(tailQueue)); i++ {
+ logChannel <- tailQueue[i]
+ }
+ tailQueue = nil
+ doTail = false
+ }
lastReadCursor := ""
+ partial := ""
for {
select {
case <-ctx.Done():
@@ -148,16 +170,7 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption
// Hit the end of the journal (so far?).
if cursor == lastReadCursor {
if doTail {
- // Flush *once* we hit the end of the journal.
- startIndex := int64(len(tailQueue)-1) - options.Tail
- if startIndex < 0 {
- startIndex = 0
- }
- for i := startIndex; i < int64(len(tailQueue)); i++ {
- logChannel <- tailQueue[i]
- }
- tailQueue = nil
- doTail = false
+ doTailFunc()
}
// Unless we follow, quit.
if !options.Follow {
@@ -190,6 +203,9 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption
return
}
if status == events.Exited {
+ if doTail {
+ doTailFunc()
+ }
return
}
continue
@@ -214,6 +230,12 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption
logrus.Errorf("Failed parse log line: %v", err)
return
}
+ if logLine.Partial() {
+ partial += logLine.Msg
+ continue
+ }
+ logLine.Msg = partial + logLine.Msg
+ partial = ""
if doTail {
tailQueue = append(tailQueue, logLine)
continue
diff --git a/libpod/info.go b/libpod/info.go
index 2eba4bbff..47fda0725 100644
--- a/libpod/info.go
+++ b/libpod/info.go
@@ -333,7 +333,7 @@ func readKernelVersion() (string, error) {
return "", err
}
f := bytes.Fields(buf)
- if len(f) < 2 {
+ if len(f) < 3 {
return string(bytes.TrimSpace(buf)), nil
}
return string(f[2]), nil
diff --git a/libpod/kube.go b/libpod/kube.go
index f5291ce60..b34734513 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -166,9 +166,83 @@ func (v *Volume) GenerateForKube() *v1.PersistentVolumeClaim {
}
}
+// YAMLPodSpec represents the same k8s API core PodSpec struct with a small
+// change and that is having Containers as a pointer to YAMLContainer.
+// Because Go doesn't omit empty struct and we want to omit Status in YAML
+// if it's empty. Fixes: GH-11998
+type YAMLPodSpec struct {
+ v1.PodSpec
+ Containers []*YAMLContainer `json:"containers"`
+}
+
+// YAMLPod represents the same k8s API core Pod struct with a small
+// change and that is having Spec as a pointer to YAMLPodSpec and
+// Status as a pointer to k8s API core PodStatus.
+// Because Go doesn't omit empty struct and we want to omit Status in YAML
+// if it's empty. Fixes: GH-11998
+type YAMLPod struct {
+ v1.Pod
+ Spec *YAMLPodSpec `json:"spec,omitempty"`
+ Status *v1.PodStatus `json:"status,omitempty"`
+}
+
+// YAMLService represents the same k8s API core Service struct with a small
+// change and that is having Status as a pointer to k8s API core ServiceStatus.
+// Because Go doesn't omit empty struct and we want to omit Status in YAML
+// if it's empty. Fixes: GH-11998
+type YAMLService struct {
+ v1.Service
+ Status *v1.ServiceStatus `json:"status,omitempty"`
+}
+
+// YAMLContainer represents the same k8s API core Container struct with a small
+// change and that is having Resources as a pointer to k8s API core ResourceRequirements.
+// Because Go doesn't omit empty struct and we want to omit Status in YAML
+// if it's empty. Fixes: GH-11998
+type YAMLContainer struct {
+ v1.Container
+ Resources *v1.ResourceRequirements `json:"resources,omitempty"`
+}
+
+// ConvertV1PodToYAMLPod takes k8s API core Pod and returns a pointer to YAMLPod
+func ConvertV1PodToYAMLPod(pod *v1.Pod) *YAMLPod {
+ cs := []*YAMLContainer{}
+ for _, cc := range pod.Spec.Containers {
+ var res *v1.ResourceRequirements = nil
+ if len(cc.Resources.Limits) > 0 || len(cc.Resources.Requests) > 0 {
+ res = &cc.Resources
+ }
+ cs = append(cs, &YAMLContainer{Container: cc, Resources: res})
+ }
+ mpo := &YAMLPod{Pod: *pod}
+ mpo.Spec = &YAMLPodSpec{PodSpec: (*pod).Spec, Containers: cs}
+ for _, ctr := range pod.Spec.Containers {
+ if ctr.SecurityContext == nil || ctr.SecurityContext.SELinuxOptions == nil {
+ continue
+ }
+ selinuxOpts := ctr.SecurityContext.SELinuxOptions
+ if selinuxOpts.User == "" && selinuxOpts.Role == "" && selinuxOpts.Type == "" && selinuxOpts.Level == "" {
+ ctr.SecurityContext.SELinuxOptions = nil
+ }
+ }
+ dnsCfg := pod.Spec.DNSConfig
+ if dnsCfg != nil && (len(dnsCfg.Nameservers)+len(dnsCfg.Searches)+len(dnsCfg.Options) > 0) {
+ mpo.Spec.DNSConfig = dnsCfg
+ }
+ status := pod.Status
+ if status.Phase != "" || len(status.Conditions) > 0 ||
+ status.Message != "" || status.Reason != "" ||
+ status.NominatedNodeName != "" || status.HostIP != "" ||
+ status.PodIP != "" || status.StartTime != nil ||
+ len(status.InitContainerStatuses) > 0 || len(status.ContainerStatuses) > 0 || status.QOSClass != "" || len(status.EphemeralContainerStatuses) > 0 {
+ mpo.Status = &status
+ }
+ return mpo
+}
+
// GenerateKubeServiceFromV1Pod creates a v1 service object from a v1 pod object
-func GenerateKubeServiceFromV1Pod(pod *v1.Pod, servicePorts []v1.ServicePort) v1.Service {
- service := v1.Service{}
+func GenerateKubeServiceFromV1Pod(pod *v1.Pod, servicePorts []v1.ServicePort) YAMLService {
+ service := YAMLService{}
selector := make(map[string]string)
selector["app"] = pod.Labels["app"]
ports := servicePorts
@@ -332,7 +406,7 @@ func newPodObject(podName string, annotations map[string]string, initCtrs, conta
InitContainers: initCtrs,
Volumes: volumes,
}
- if dnsOptions != nil {
+ if dnsOptions != nil && (len(dnsOptions.Nameservers)+len(dnsOptions.Searches)+len(dnsOptions.Options) > 0) {
ps.DNSConfig = dnsOptions
}
p := v1.Pod{
@@ -447,11 +521,6 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, []
kubeVolumes = append(kubeVolumes, volumes...)
}
- envVariables, err := libpodEnvVarsToKubeEnvVars(c.config.Spec.Process.Env)
- if err != nil {
- return kubeContainer, kubeVolumes, nil, annotations, err
- }
-
portmappings, err := c.PortMappings()
if err != nil {
return kubeContainer, kubeVolumes, nil, annotations, err
@@ -489,15 +558,23 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, []
kubeContainer.Command = nil
}
+ if c.WorkingDir() != "/" && imgData.Config.WorkingDir != c.WorkingDir() {
+ kubeContainer.WorkingDir = c.WorkingDir()
+ }
+
if imgData.User == c.User() {
kubeSec.RunAsGroup, kubeSec.RunAsUser = nil, nil
}
- kubeContainer.WorkingDir = c.WorkingDir()
+ envVariables, err := libpodEnvVarsToKubeEnvVars(c.config.Spec.Process.Env, imgData.Config.Env)
+ if err != nil {
+ return kubeContainer, kubeVolumes, nil, annotations, err
+ }
+ kubeContainer.Env = envVariables
+
kubeContainer.Ports = ports
// This should not be applicable
//container.EnvFromSource =
- kubeContainer.Env = envVariables
kubeContainer.SecurityContext = kubeSec
kubeContainer.StdinOnce = false
kubeContainer.TTY = c.config.Spec.Process.Terminal
@@ -600,9 +677,14 @@ func ocicniPortMappingToContainerPort(portMappings []ocicni.PortMapping) ([]v1.C
}
// libpodEnvVarsToKubeEnvVars converts a key=value string slice to []v1.EnvVar
-func libpodEnvVarsToKubeEnvVars(envs []string) ([]v1.EnvVar, error) {
+func libpodEnvVarsToKubeEnvVars(envs []string, imageEnvs []string) ([]v1.EnvVar, error) {
defaultEnv := env.DefaultEnvVariables()
envVars := make([]v1.EnvVar, 0, len(envs))
+ imageMap := make(map[string]string, len(imageEnvs))
+ for _, ie := range envs {
+ split := strings.SplitN(ie, "=", 2)
+ imageMap[split[0]] = split[1]
+ }
for _, e := range envs {
split := strings.SplitN(e, "=", 2)
if len(split) != 2 {
@@ -611,6 +693,9 @@ func libpodEnvVarsToKubeEnvVars(envs []string) ([]v1.EnvVar, error) {
if defaultEnv[split[0]] == split[1] {
continue
}
+ if imageMap[split[0]] == split[1] {
+ continue
+ }
ev := v1.EnvVar{
Name: split[0],
Value: split[1],
@@ -808,33 +893,42 @@ func generateKubeSecurityContext(c *Container) (*v1.SecurityContext, error) {
capabilities = newCaps
}
+ sc := v1.SecurityContext{
+ // RunAsNonRoot is an optional parameter; our first implementations should be root only; however
+ // I'm leaving this as a bread-crumb for later
+ //RunAsNonRoot: &nonRoot,
+ }
+ if capabilities != nil {
+ sc.Capabilities = capabilities
+ }
var selinuxOpts v1.SELinuxOptions
opts := strings.SplitN(c.config.Spec.Annotations[define.InspectAnnotationLabel], ":", 2)
- if len(opts) == 2 {
+ switch len(opts) {
+ case 2:
switch opts[0] {
case "type":
selinuxOpts.Type = opts[1]
+ sc.SELinuxOptions = &selinuxOpts
case "level":
selinuxOpts.Level = opts[1]
+ sc.SELinuxOptions = &selinuxOpts
}
- }
- if len(opts) == 1 {
+ case 1:
if opts[0] == "disable" {
selinuxOpts.Type = "spc_t"
+ sc.SELinuxOptions = &selinuxOpts
}
}
- sc := v1.SecurityContext{
- Capabilities: capabilities,
- Privileged: &privileged,
- SELinuxOptions: &selinuxOpts,
- // RunAsNonRoot is an optional parameter; our first implementations should be root only; however
- // I'm leaving this as a bread-crumb for later
- //RunAsNonRoot: &nonRoot,
- ReadOnlyRootFilesystem: &ro,
- AllowPrivilegeEscalation: &allowPrivEscalation,
+ if !allowPrivEscalation {
+ sc.AllowPrivilegeEscalation = &allowPrivEscalation
+ }
+ if privileged {
+ sc.Privileged = &privileged
+ }
+ if ro {
+ sc.ReadOnlyRootFilesystem = &ro
}
-
if c.User() != "" {
if !c.batched {
c.lock.Lock()
diff --git a/libpod/lock/shm/shm_lock.go b/libpod/lock/shm/shm_lock.go
index 322e92a8f..fea02a619 100644
--- a/libpod/lock/shm/shm_lock.go
+++ b/libpod/lock/shm/shm_lock.go
@@ -130,8 +130,17 @@ func (locks *SHMLocks) AllocateSemaphore() (uint32, error) {
// semaphore indexes, and can still return error codes.
retCode := C.allocate_semaphore(locks.lockStruct)
if retCode < 0 {
+ var err = syscall.Errno(-1 * retCode)
// Negative errno returned
- return 0, syscall.Errno(-1 * retCode)
+ if errors.Is(err, syscall.ENOSPC) {
+ // ENOSPC expands to "no space left on device". While it is technically true
+ // that there's no room in the SHM inn for this lock, this tends to send normal people
+ // down the path of checking disk-space which is not actually their problem.
+ // Give a clue that it's actually due to num_locks filling up.
+ var errFull = errors.Errorf("allocation failed; exceeded num_locks (%d)", locks.maxLocks)
+ return uint32(retCode), errFull
+ }
+ return uint32(retCode), syscall.Errno(-1 * retCode)
}
return uint32(retCode), nil
diff --git a/libpod/network/cni/cni_types.go b/libpod/network/cni/cni_types.go
index 91fd1c27b..35548f4f9 100644
--- a/libpod/network/cni/cni_types.go
+++ b/libpod/network/cni/cni_types.go
@@ -175,7 +175,7 @@ func newIPAMLocalHostRange(subnet types.IPNet, leaseRange *types.LeaseRange, gw
Subnet: subnet.String(),
}
- // an user provided a range, we add it here
+ // a user provided a range, we add it here
if leaseRange != nil {
if leaseRange.StartIP != nil {
hostRange.RangeStart = leaseRange.StartIP.String()
diff --git a/libpod/network/cni/run.go b/libpod/network/cni/run.go
index 14634262c..3f78d79a4 100644
--- a/libpod/network/cni/run.go
+++ b/libpod/network/cni/run.go
@@ -199,10 +199,8 @@ func getRuntimeConfig(netns, conName, conID, networkName string, ports []cniPort
IfName: opts.InterfaceName,
Args: [][2]string{
{"IgnoreUnknown", "1"},
- // FIXME: Should we set the K8S args?
- //{"K8S_POD_NAMESPACE", conName},
- //{"K8S_POD_INFRA_CONTAINER_ID", conID},
- // K8S_POD_NAME is used by dnsname to get the container name
+ // Do not set the K8S env vars, see https://github.com/containers/podman/issues/12083.
+ // Only K8S_POD_NAME is used by dnsname to get the container name.
{"K8S_POD_NAME", conName},
},
CapabilityArgs: map[string]interface{}{},
diff --git a/libpod/networking_slirp4netns.go b/libpod/networking_slirp4netns.go
index c06d215e1..e24b54032 100644
--- a/libpod/networking_slirp4netns.go
+++ b/libpod/networking_slirp4netns.go
@@ -16,6 +16,7 @@ import (
"syscall"
"time"
+ "github.com/containernetworking/plugins/pkg/ns"
"github.com/containers/podman/v3/pkg/errorhandling"
"github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/rootlessport"
@@ -58,6 +59,8 @@ type slirp4netnsNetworkOptions struct {
outboundAddr6 string
}
+const ipv6ConfDefaultAcceptDadSysctl = "/proc/sys/net/ipv6/conf/default/accept_dad"
+
func checkSlirpFlags(path string) (*slirpFeatures, error) {
cmd := exec.Command(path, "--help")
out, err := cmd.CombinedOutput()
@@ -297,6 +300,39 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error {
}
cmd.Stdout = logFile
cmd.Stderr = logFile
+
+ var slirpReadyChan (chan struct{})
+
+ if netOptions.enableIPv6 {
+ slirpReadyChan = make(chan struct{})
+ defer close(slirpReadyChan)
+ go func() {
+ err := ns.WithNetNSPath(netnsPath, func(_ ns.NetNS) error {
+ // Duplicate Address Detection slows the ipv6 setup down for 1-2 seconds.
+ // Since slirp4netns is run it is own namespace and not directly routed
+ // we can skip this to make the ipv6 address immediately available.
+ // We change the default to make sure the slirp tap interface gets the
+ // correct value assigned so DAD is disabled for it
+ // Also make sure to change this value back to the original after slirp4netns
+ // is ready in case users rely on this sysctl.
+ orgValue, err := ioutil.ReadFile(ipv6ConfDefaultAcceptDadSysctl)
+ if err != nil {
+ return err
+ }
+ err = ioutil.WriteFile(ipv6ConfDefaultAcceptDadSysctl, []byte("0"), 0644)
+ if err != nil {
+ return err
+ }
+ // wait for slirp to finish setup
+ <-slirpReadyChan
+ return ioutil.WriteFile(ipv6ConfDefaultAcceptDadSysctl, orgValue, 0644)
+ })
+ if err != nil {
+ logrus.Warnf("failed to set net.ipv6.conf.default.accept_dad sysctl: %v", err)
+ }
+ }()
+ }
+
if err := cmd.Start(); err != nil {
return errors.Wrapf(err, "failed to start slirp4netns process")
}
@@ -310,6 +346,9 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error {
if err := waitForSync(syncR, cmd, logFile, 1*time.Second); err != nil {
return err
}
+ if slirpReadyChan != nil {
+ slirpReadyChan <- struct{}{}
+ }
// Set a default slirp subnet. Parsing a string with the net helper is easier than building the struct myself
_, ctr.slirp4netnsSubnet, _ = net.ParseCIDR(defaultSlirp4netnsSubnet)
diff --git a/libpod/runtime.go b/libpod/runtime.go
index c22d87324..a208b6db4 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -541,6 +541,8 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) {
return err
}
if became {
+ // Check if the pause process was created. If it was created, then
+ // move it to its own systemd scope.
utils.MovePauseProcessToScope(pausePid)
os.Exit(ret)
}
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 7d3891f6e..f27e854a4 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -322,15 +322,6 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai
}
}
- if ctr.config.Name == "" {
- name, err := r.generateName()
- if err != nil {
- return nil, err
- }
-
- ctr.config.Name = name
- }
-
// Check CGroup parent sanity, and set it if it was not set.
// Only if we're actually configuring CGroups.
if !ctr.config.NoCgroups {
diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go
index 7571fdfff..de00eb8e0 100644
--- a/libpod/runtime_pod_linux.go
+++ b/libpod/runtime_pod_linux.go
@@ -43,18 +43,6 @@ func (r *Runtime) NewPod(ctx context.Context, p specgen.PodSpecGenerator, option
}
}
- if pod.config.Name == "" {
- name, err := r.generateName()
- if err != nil {
- return nil, err
- }
- pod.config.Name = name
- }
-
- if p.InfraContainerSpec != nil && p.InfraContainerSpec.Hostname == "" {
- p.InfraContainerSpec.Hostname = pod.config.Name
- }
-
// Allocate a lock for the pod
lock, err := r.lockManager.AllocateLock()
if err != nil {
@@ -131,9 +119,33 @@ func (r *Runtime) NewPod(ctx context.Context, p specgen.PodSpecGenerator, option
logrus.Infof("Pod has an infra container, but shares no namespaces")
}
- if err := r.state.AddPod(pod); err != nil {
- return nil, errors.Wrapf(err, "error adding pod to state")
+ // Unless the user has specified a name, use a randomly generated one.
+ // Note that name conflicts may occur (see #11735), so we need to loop.
+ generateName := pod.config.Name == ""
+ var addPodErr error
+ for {
+ if generateName {
+ name, err := r.generateName()
+ if err != nil {
+ return nil, err
+ }
+ pod.config.Name = name
+ }
+
+ if p.InfraContainerSpec != nil && p.InfraContainerSpec.Hostname == "" {
+ p.InfraContainerSpec.Hostname = pod.config.Name
+ }
+ if addPodErr = r.state.AddPod(pod); addPodErr == nil {
+ return pod, nil
+ }
+ if !generateName || (errors.Cause(addPodErr) != define.ErrPodExists && errors.Cause(addPodErr) != define.ErrCtrExists) {
+ break
+ }
}
+ if addPodErr != nil {
+ return nil, errors.Wrapf(addPodErr, "error adding pod to state")
+ }
+
return pod, nil
}
@@ -177,10 +189,9 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool)
if err != nil {
return err
}
-
numCtrs := len(ctrs)
- // If the only container in the pod is the pause container, remove the pod and container unconditionally.
+ // If the only running container in the pod is the pause container, remove the pod and container unconditionally.
pauseCtrID := p.state.InfraContainerID
if numCtrs == 1 && ctrs[0].ID() == pauseCtrID {
removeCtrs = true
@@ -264,6 +275,15 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool)
}
}
+ // Clear infra container ID before we remove the infra container.
+ // There is a potential issue if we don't do that, and removal is
+ // interrupted between RemoveAllContainers() below and the pod's removal
+ // later - we end up with a reference to a nonexistent infra container.
+ p.state.InfraContainerID = ""
+ if err := p.save(); err != nil {
+ return err
+ }
+
// Remove all containers in the pod from the state.
if err := r.state.RemovePodContainers(p); err != nil {
// If this fails, there isn't much more we can do.
diff --git a/nix/default-arm64.nix b/nix/default-arm64.nix
index 8868788ae..a38cef04a 100644
--- a/nix/default-arm64.nix
+++ b/nix/default-arm64.nix
@@ -59,7 +59,8 @@ let
self = with pkgs; buildGoModule rec {
name = "podman";
- src = ./..;
+ src = builtins.filterSource
+ (path: type: !(type == "directory" && baseNameOf path == "bin")) ./..;
vendorSha256 = null;
doCheck = false;
enableParallelBuilding = true;
diff --git a/nix/default.nix b/nix/default.nix
index 4d15532c2..9a4b372a4 100644
--- a/nix/default.nix
+++ b/nix/default.nix
@@ -57,7 +57,8 @@ let
self = with pkgs; buildGoModule rec {
name = "podman";
- src = ./..;
+ src = builtins.filterSource
+ (path: type: !(type == "directory" && baseNameOf path == "bin")) ./..;
vendorSha256 = null;
doCheck = false;
enableParallelBuilding = true;
diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go
index 606c52e41..6152f1c02 100644
--- a/pkg/api/handlers/compat/images_build.go
+++ b/pkg/api/handlers/compat/images_build.go
@@ -151,22 +151,19 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
var m = []string{}
if err := json.Unmarshal([]byte(query.Dockerfile), &m); err != nil {
// it's not json, assume just a string
- m = append(m, query.Dockerfile)
+ m = []string{filepath.Join(contextDirectory, query.Dockerfile)}
}
containerFiles = m
} else {
- containerFiles = []string{"Dockerfile"}
+ containerFiles = []string{filepath.Join(contextDirectory, "Dockerfile")}
if utils.IsLibpodRequest(r) {
- containerFiles = []string{"Containerfile"}
- if _, err = os.Stat(filepath.Join(contextDirectory, "Containerfile")); err != nil {
- if _, err1 := os.Stat(filepath.Join(contextDirectory, "Dockerfile")); err1 == nil {
- containerFiles = []string{"Dockerfile"}
- } else {
+ containerFiles = []string{filepath.Join(contextDirectory, "Containerfile")}
+ if _, err = os.Stat(containerFiles[0]); err != nil {
+ containerFiles = []string{filepath.Join(contextDirectory, "Dockerfile")}
+ if _, err1 := os.Stat(containerFiles[0]); err1 != nil {
utils.BadRequest(w, "dockerfile", query.Dockerfile, err)
}
}
- } else {
- containerFiles = []string{"Dockerfile"}
}
}
diff --git a/pkg/api/server/handler_rid.go b/pkg/api/server/handler_rid.go
index b624b99a6..7dcf436f7 100644
--- a/pkg/api/server/handler_rid.go
+++ b/pkg/api/server/handler_rid.go
@@ -2,6 +2,7 @@ package server
import (
"fmt"
+ "io/ioutil"
"net/http"
"github.com/containers/podman/v3/pkg/api/types"
@@ -15,7 +16,13 @@ import (
// and Apache style request logging
func referenceIDHandler() mux.MiddlewareFunc {
return func(h http.Handler) http.Handler {
- return handlers.CombinedLoggingHandler(logrus.StandardLogger().Out,
+ // Only log Apache access_log-like entries at Info level or below
+ out := ioutil.Discard
+ if logrus.IsLevelEnabled(logrus.InfoLevel) {
+ out = logrus.StandardLogger().Out
+ }
+
+ return handlers.CombinedLoggingHandler(out,
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
rid := r.Header.Get("X-Reference-Id")
if rid == "" {
diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go
index 95981226c..f66669256 100644
--- a/pkg/api/server/register_images.go
+++ b/pkg/api/server/register_images.go
@@ -103,7 +103,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// - application/json
// responses:
// 200:
- // $ref: "#/responses/DockerImageSummary"
+ // $ref: "#/responses/DockerImageSummaryResponse"
// 500:
// $ref: '#/responses/InternalError'
r.Handle(VersionedPath("/images/json"), s.APIHandler(compat.GetImages)).Methods(http.MethodGet)
@@ -831,7 +831,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// - application/json
// responses:
// 200:
- // $ref: "#/responses/DockerImageSummary"
+ // $ref: "#/responses/LibpodImageSummaryResponse"
// 500:
// $ref: '#/responses/InternalError'
r.Handle(VersionedPath("/libpod/images/json"), s.APIHandler(libpod.GetImages)).Methods(http.MethodGet)
diff --git a/pkg/api/server/swagger.go b/pkg/api/server/swagger.go
index 0fd66652e..3f8f6f9c5 100644
--- a/pkg/api/server/swagger.go
+++ b/pkg/api/server/swagger.go
@@ -6,6 +6,7 @@ import (
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/entities/reports"
"github.com/containers/podman/v3/pkg/errorhandling"
+ docker "github.com/docker/docker/api/types"
)
// No such image
@@ -134,9 +135,16 @@ type swagPodAlreadyStopped struct {
}
}
-// Image summary
-// swagger:response DockerImageSummary
-type swagImageSummary struct {
+// Image summary for compat API
+// swagger:response DockerImageSummaryResponse
+type swagDockerImageSummaryResponse struct {
+ // in:body
+ Body []docker.ImageSummary
+}
+
+// Image summary for libpod API
+// swagger:response LibpodImageSummaryResponse
+type swagLibpodImageSummaryResponse struct {
// in:body
Body []entities.ImageSummary
}
diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go
index e2c46e481..2fe86ca39 100644
--- a/pkg/bindings/connection.go
+++ b/pkg/bindings/connection.go
@@ -379,6 +379,11 @@ func (h *APIResponse) IsClientError() bool {
return h.Response.StatusCode/100 == 4
}
+// IsConflictError returns true if the response code is 409
+func (h *APIResponse) IsConflictError() bool {
+ return h.Response.StatusCode == 409
+}
+
// IsServerError returns true if the response code is 5xx
func (h *APIResponse) IsServerError() bool {
return h.Response.StatusCode/100 == 5
diff --git a/pkg/bindings/containers/attach.go b/pkg/bindings/containers/attach.go
index 725d06648..32a8978d9 100644
--- a/pkg/bindings/containers/attach.go
+++ b/pkg/bindings/containers/attach.go
@@ -214,7 +214,7 @@ func Attach(ctx context.Context, nameOrID string, stdin io.Reader, stdout io.Wri
// Read multiplexed channels and write to appropriate stream
fd, l, err := DemuxHeader(socket, buffer)
if err != nil {
- if errors.Is(err, io.EOF) {
+ if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
return nil
}
return err
@@ -531,7 +531,7 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, options *ExecStar
// Read multiplexed channels and write to appropriate stream
fd, l, err := DemuxHeader(socket, buffer)
if err != nil {
- if errors.Is(err, io.EOF) {
+ if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
return nil
}
return err
diff --git a/pkg/bindings/containers/logs.go b/pkg/bindings/containers/logs.go
index 67db94487..37ffdf0a5 100644
--- a/pkg/bindings/containers/logs.go
+++ b/pkg/bindings/containers/logs.go
@@ -39,7 +39,7 @@ func Logs(ctx context.Context, nameOrID string, options *LogOptions, stdoutChan,
for {
fd, l, err := DemuxHeader(response.Body, buffer)
if err != nil {
- if errors.Is(err, io.EOF) {
+ if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
return nil
}
return err
diff --git a/pkg/bindings/errors.go b/pkg/bindings/errors.go
index 9c311d912..ec837b39c 100644
--- a/pkg/bindings/errors.go
+++ b/pkg/bindings/errors.go
@@ -12,17 +12,22 @@ var (
ErrNotImplemented = errors.New("function not implemented")
)
-func handleError(data []byte) error {
- e := errorhandling.ErrorModel{}
- if err := json.Unmarshal(data, &e); err != nil {
+func handleError(data []byte, unmarshalErrorInto interface{}) error {
+ if err := json.Unmarshal(data, unmarshalErrorInto); err != nil {
return err
}
- return e
+ return unmarshalErrorInto.(error)
}
// Process drains the response body, and processes the HTTP status code
// Note: Closing the response.Body is left to the caller
func (h APIResponse) Process(unmarshalInto interface{}) error {
+ return h.ProcessWithError(unmarshalInto, &errorhandling.ErrorModel{})
+}
+
+// Process drains the response body, and processes the HTTP status code
+// Note: Closing the response.Body is left to the caller
+func (h APIResponse) ProcessWithError(unmarshalInto interface{}, unmarshalErrorInto interface{}) error {
data, err := ioutil.ReadAll(h.Response.Body)
if err != nil {
return errors.Wrap(err, "unable to process API response")
@@ -33,14 +38,22 @@ func (h APIResponse) Process(unmarshalInto interface{}) error {
}
return nil
}
+
+ if h.IsConflictError() {
+ return handleError(data, unmarshalErrorInto)
+ }
+
// TODO should we add a debug here with the response code?
- return handleError(data)
+ return handleError(data, &errorhandling.ErrorModel{})
}
func CheckResponseCode(inError error) (int, error) {
- e, ok := inError.(errorhandling.ErrorModel)
- if !ok {
+ switch e := inError.(type) {
+ case *errorhandling.ErrorModel:
+ return e.Code(), nil
+ case *errorhandling.PodConflictErrorModel:
+ return e.Code(), nil
+ default:
return -1, errors.New("error is not type ErrorModel")
}
- return e.Code(), nil
}
diff --git a/pkg/bindings/pods/pods.go b/pkg/bindings/pods/pods.go
index a1a431a3b..3b5832373 100644
--- a/pkg/bindings/pods/pods.go
+++ b/pkg/bindings/pods/pods.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/podman/v3/pkg/api/handlers"
"github.com/containers/podman/v3/pkg/bindings"
"github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/podman/v3/pkg/errorhandling"
jsoniter "github.com/json-iterator/go"
)
@@ -97,7 +98,7 @@ func Kill(ctx context.Context, nameOrID string, options *KillOptions) (*entities
}
defer response.Body.Close()
- return &report, response.Process(&report)
+ return &report, response.ProcessWithError(&report, &errorhandling.PodConflictErrorModel{})
}
// Pause pauses all running containers in a given pod.
@@ -117,7 +118,7 @@ func Pause(ctx context.Context, nameOrID string, options *PauseOptions) (*entiti
}
defer response.Body.Close()
- return &report, response.Process(&report)
+ return &report, response.ProcessWithError(&report, &errorhandling.PodConflictErrorModel{})
}
// Prune by default removes all non-running pods in local storage.
@@ -184,7 +185,7 @@ func Restart(ctx context.Context, nameOrID string, options *RestartOptions) (*en
}
defer response.Body.Close()
- return &report, response.Process(&report)
+ return &report, response.ProcessWithError(&report, &errorhandling.PodConflictErrorModel{})
}
// Remove deletes a Pod from from local storage. The optional force parameter denotes
@@ -232,7 +233,8 @@ func Start(ctx context.Context, nameOrID string, options *StartOptions) (*entiti
report.Id = nameOrID
return &report, nil
}
- return &report, response.Process(&report)
+
+ return &report, response.ProcessWithError(&report, &errorhandling.PodConflictErrorModel{})
}
// Stop stops all containers in a Pod. The optional timeout parameter can be
@@ -260,7 +262,7 @@ func Stop(ctx context.Context, nameOrID string, options *StopOptions) (*entities
report.Id = nameOrID
return &report, nil
}
- return &report, response.Process(&report)
+ return &report, response.ProcessWithError(&report, &errorhandling.PodConflictErrorModel{})
}
// Top gathers statistics about the running processes in a pod. The nameOrID can be a pod name
@@ -316,7 +318,7 @@ func Unpause(ctx context.Context, nameOrID string, options *UnpauseOptions) (*en
}
defer response.Body.Close()
- return &report, response.Process(&report)
+ return &report, response.ProcessWithError(&report, &errorhandling.PodConflictErrorModel{})
}
// Stats display resource-usage statistics of one or more pods.
diff --git a/pkg/bindings/test/common_test.go b/pkg/bindings/test/common_test.go
index 91ebe21fc..d996595bf 100644
--- a/pkg/bindings/test/common_test.go
+++ b/pkg/bindings/test/common_test.go
@@ -225,12 +225,23 @@ func (b *bindingTest) RunTopContainer(containerName *string, podName *string) (s
// This method creates a pod with the given pod name.
// Podname is an optional parameter
func (b *bindingTest) Podcreate(name *string) {
+ b.PodcreateAndExpose(name, nil)
+}
+
+// This method creates a pod with the given pod name and publish port.
+// Podname is an optional parameter
+// port is an optional parameter
+func (b *bindingTest) PodcreateAndExpose(name *string, port *string) {
+ command := []string{"pod", "create"}
if name != nil {
podname := *name
- b.runPodman([]string{"pod", "create", "--name", podname}).Wait(45)
- } else {
- b.runPodman([]string{"pod", "create"}).Wait(45)
+ command = append(command, "--name", podname)
+ }
+ if port != nil {
+ podport := *port
+ command = append(command, "--publish", podport)
}
+ b.runPodman(command).Wait(45)
}
// StringInSlice returns a boolean based on whether a given
diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go
index b9ed67255..0f535bc31 100644
--- a/pkg/bindings/test/containers_test.go
+++ b/pkg/bindings/test/containers_test.go
@@ -259,6 +259,7 @@ var _ = Describe("Podman containers ", func() {
_, err = bt.RunTopContainer(&name, nil)
Expect(err).To(BeNil())
go func() {
+ defer GinkgoRecover()
exitCode, err = containers.Wait(bt.conn, name, nil)
errChan <- err
close(errChan)
@@ -281,6 +282,7 @@ var _ = Describe("Podman containers ", func() {
_, err := bt.RunTopContainer(&name, nil)
Expect(err).To(BeNil())
go func() {
+ defer GinkgoRecover()
exitCode, err = containers.Wait(bt.conn, name, new(containers.WaitOptions).WithCondition([]define.ContainerStatus{pause}))
errChan <- err
close(errChan)
@@ -366,7 +368,10 @@ var _ = Describe("Podman containers ", func() {
opts := new(containers.LogOptions).WithStdout(true).WithFollow(true)
go func() {
- containers.Logs(bt.conn, r.ID, opts, stdoutChan, nil)
+ defer GinkgoRecover()
+ err := containers.Logs(bt.conn, r.ID, opts, stdoutChan, nil)
+ close(stdoutChan)
+ Expect(err).ShouldNot(HaveOccurred())
}()
o := <-stdoutChan
o = strings.TrimSpace(o)
diff --git a/pkg/bindings/test/pods_test.go b/pkg/bindings/test/pods_test.go
index 5331cf439..879d4d00d 100644
--- a/pkg/bindings/test/pods_test.go
+++ b/pkg/bindings/test/pods_test.go
@@ -1,6 +1,7 @@
package test_bindings
import (
+ "fmt"
"net/http"
"strings"
"time"
@@ -9,7 +10,9 @@ import (
"github.com/containers/podman/v3/pkg/bindings"
"github.com/containers/podman/v3/pkg/bindings/pods"
"github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/podman/v3/pkg/errorhandling"
"github.com/containers/podman/v3/pkg/specgen"
+ "github.com/containers/podman/v3/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
@@ -208,6 +211,29 @@ var _ = Describe("Podman pods", func() {
}
})
+ It("start pod with port conflict", func() {
+ randomport, err := utils.GetRandomPort()
+ Expect(err).To(BeNil())
+
+ portPublish := fmt.Sprintf("%d:%d", randomport, randomport)
+ var podwithport string = "newpodwithport"
+ bt.PodcreateAndExpose(&podwithport, &portPublish)
+
+ // Start pod and expose port 12345
+ _, err = pods.Start(bt.conn, podwithport, nil)
+ Expect(err).To(BeNil())
+
+ // Start another pod and expose same port 12345
+ var podwithport2 string = "newpodwithport2"
+ bt.PodcreateAndExpose(&podwithport2, &portPublish)
+
+ _, err = pods.Start(bt.conn, podwithport2, nil)
+ Expect(err).ToNot(BeNil())
+ code, _ := bindings.CheckResponseCode(err)
+ Expect(code).To(BeNumerically("==", http.StatusConflict))
+ Expect(err).To(BeAssignableToTypeOf(&errorhandling.PodConflictErrorModel{}))
+ })
+
It("start stop restart pod", func() {
// Start an invalid pod
_, err = pods.Start(bt.conn, "dummyName", nil)
diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go
index f1ef538e4..d0c090012 100644
--- a/pkg/cgroups/cgroups.go
+++ b/pkg/cgroups/cgroups.go
@@ -461,10 +461,10 @@ func (c *CgroupControl) CreateSystemdUnit(path string) error {
return systemdCreate(path, conn)
}
-// GetUserConnection returns an user connection to D-BUS
+// GetUserConnection returns a user connection to D-BUS
func GetUserConnection(uid int) (*systemdDbus.Conn, error) {
return systemdDbus.NewConnection(func() (*dbus.Conn, error) {
- return dbusAuthConnection(uid, dbus.SessionBusPrivate)
+ return dbusAuthConnection(uid, dbus.SessionBusPrivateNoAutoStartup)
})
}
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index 5a469d981..6d93ad403 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -50,6 +50,7 @@ func (i *Image) Id() string { // nolint
return i.ID
}
+// swagger:model LibpodImageSummary
type ImageSummary struct {
ID string `json:"Id"`
ParentId string // nolint
diff --git a/pkg/domain/infra/abi/generate.go b/pkg/domain/infra/abi/generate.go
index 081a2464b..a4d6bcf86 100644
--- a/pkg/domain/infra/abi/generate.go
+++ b/pkg/domain/infra/abi/generate.go
@@ -124,8 +124,7 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string,
if err != nil {
return nil, err
}
-
- b, err := generateKubeYAML(po)
+ b, err := generateKubeYAML(libpod.ConvertV1PodToYAMLPod(po))
if err != nil {
return nil, err
}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index b638bfe24..c4d62bd89 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -226,7 +226,7 @@ func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []st
for _, name := range namesOrIds {
inspect, err := containers.Inspect(ic.ClientCtx, name, options)
if err != nil {
- errModel, ok := err.(errorhandling.ErrorModel)
+ errModel, ok := err.(*errorhandling.ErrorModel)
if !ok {
return nil, nil, err
}
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index 9a746d68c..ab2a93c75 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -188,7 +188,7 @@ func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts en
for _, i := range namesOrIDs {
r, err := images.GetImage(ir.ClientCtx, i, options)
if err != nil {
- errModel, ok := err.(errorhandling.ErrorModel)
+ errModel, ok := err.(*errorhandling.ErrorModel)
if !ok {
return nil, nil, err
}
diff --git a/pkg/domain/infra/tunnel/network.go b/pkg/domain/infra/tunnel/network.go
index 7e59e44c2..7c183b1ac 100644
--- a/pkg/domain/infra/tunnel/network.go
+++ b/pkg/domain/infra/tunnel/network.go
@@ -23,7 +23,7 @@ func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []stri
for _, name := range namesOrIds {
report, err := network.Inspect(ic.ClientCtx, name, options)
if err != nil {
- errModel, ok := err.(errorhandling.ErrorModel)
+ errModel, ok := err.(*errorhandling.ErrorModel)
if !ok {
return nil, nil, err
}
diff --git a/pkg/domain/infra/tunnel/secrets.go b/pkg/domain/infra/tunnel/secrets.go
index 6337c7fbe..e5fa200bd 100644
--- a/pkg/domain/infra/tunnel/secrets.go
+++ b/pkg/domain/infra/tunnel/secrets.go
@@ -28,7 +28,7 @@ func (ic *ContainerEngine) SecretInspect(ctx context.Context, nameOrIDs []string
for _, name := range nameOrIDs {
inspected, err := secrets.Inspect(ic.ClientCtx, name, nil)
if err != nil {
- errModel, ok := err.(errorhandling.ErrorModel)
+ errModel, ok := err.(*errorhandling.ErrorModel)
if !ok {
return nil, nil, err
}
@@ -67,7 +67,7 @@ func (ic *ContainerEngine) SecretRm(ctx context.Context, nameOrIDs []string, opt
for _, name := range nameOrIDs {
secret, err := secrets.Inspect(ic.ClientCtx, name, nil)
if err != nil {
- errModel, ok := err.(errorhandling.ErrorModel)
+ errModel, ok := err.(*errorhandling.ErrorModel)
if !ok {
return nil, err
}
diff --git a/pkg/domain/infra/tunnel/volumes.go b/pkg/domain/infra/tunnel/volumes.go
index 2b2b2c2a1..a3d9e1b6d 100644
--- a/pkg/domain/infra/tunnel/volumes.go
+++ b/pkg/domain/infra/tunnel/volumes.go
@@ -56,7 +56,7 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
for _, id := range namesOrIds {
data, err := volumes.Inspect(ic.ClientCtx, id, nil)
if err != nil {
- errModel, ok := err.(errorhandling.ErrorModel)
+ errModel, ok := err.(*errorhandling.ErrorModel)
if !ok {
return nil, nil, err
}
diff --git a/pkg/errorhandling/errorhandling.go b/pkg/errorhandling/errorhandling.go
index 6adbc9f34..fcb0f7881 100644
--- a/pkg/errorhandling/errorhandling.go
+++ b/pkg/errorhandling/errorhandling.go
@@ -83,6 +83,12 @@ func Contains(err error, sub error) bool {
return strings.Contains(err.Error(), sub.Error())
}
+// PodConflictErrorModel is used in remote connections with podman
+type PodConflictErrorModel struct {
+ Errs []string
+ Id string //nolint
+}
+
// ErrorModel is used in remote connections with podman
type ErrorModel struct {
// API root cause formatted for automated parsing
@@ -106,3 +112,11 @@ func (e ErrorModel) Cause() error {
func (e ErrorModel) Code() int {
return e.ResponseCode
}
+
+func (e PodConflictErrorModel) Error() string {
+ return strings.Join(e.Errs, ",")
+}
+
+func (e PodConflictErrorModel) Code() int {
+ return 409
+}
diff --git a/pkg/machine/ignition.go b/pkg/machine/ignition.go
index e211f5ea6..42d729458 100644
--- a/pkg/machine/ignition.go
+++ b/pkg/machine/ignition.go
@@ -304,6 +304,24 @@ machine_enabled=true
},
})
+ setDockerHost := `export DOCKER_HOST="unix://$(podman info -f "{{.Host.RemoteSocket.Path}}")"
+`
+
+ files = append(files, File{
+ Node: Node{
+ Group: getNodeGrp("root"),
+ Path: "/etc/profile.d/docker-host.sh",
+ User: getNodeUsr("root"),
+ },
+ FileEmbedded1: FileEmbedded1{
+ Append: nil,
+ Contents: Resource{
+ Source: encodeDataURLPtr(setDockerHost),
+ },
+ Mode: intToPtr(0644),
+ },
+ })
+
return files
}
diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go
index 6a6397257..8007e5d8e 100644
--- a/pkg/specgenutil/specgen.go
+++ b/pkg/specgenutil/specgen.go
@@ -133,12 +133,14 @@ func getMemoryLimits(s *specgen.SpecGenerator, c *entities.ContainerCreateOption
if err != nil {
return nil, errors.Wrapf(err, "invalid value for memory")
}
- memory.Limit = &ml
- if c.MemorySwap == "" {
- limit := 2 * ml
- memory.Swap = &(limit)
+ if ml > 0 {
+ memory.Limit = &ml
+ if c.MemorySwap == "" {
+ limit := 2 * ml
+ memory.Swap = &(limit)
+ }
+ hasLimits = true
}
- hasLimits = true
}
if m := c.MemoryReservation; len(m) > 0 {
mr, err := units.RAMInBytes(m)
diff --git a/pkg/systemd/dbus.go b/pkg/systemd/dbus.go
index c49f537b6..04aaa117a 100644
--- a/pkg/systemd/dbus.go
+++ b/pkg/systemd/dbus.go
@@ -84,7 +84,7 @@ func IsSystemdSessionValid(uid int) bool {
return true
}
-// GetDbusConnection returns an user connection to D-BUS
+// GetDbusConnection returns a user connection to D-BUS
func GetLogindConnection(uid int) (*godbus.Conn, error) {
return dbusAuthConnectionLogind(uid)
}
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
index 20ed72c59..dbf51f4e4 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -685,7 +685,7 @@ func SkipIfContainerized(reason string) {
// PodmanAsUser is the exec call to podman on the filesystem with the specified uid/gid and environment
func (p *PodmanTestIntegration) PodmanAsUser(args []string, uid, gid uint32, cwd string, env []string) *PodmanSessionIntegration {
- podmanSession := p.PodmanAsUserBase(args, uid, gid, cwd, env, false, false, nil)
+ podmanSession := p.PodmanAsUserBase(args, uid, gid, cwd, env, false, false, nil, nil)
return &PodmanSessionIntegration{podmanSession}
}
diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go
index 07515fe7b..21f4ad8fa 100644
--- a/test/e2e/generate_kube_test.go
+++ b/test/e2e/generate_kube_test.go
@@ -67,6 +67,10 @@ var _ = Describe("Podman generate kube", func() {
err := yaml.Unmarshal(kube.Out.Contents(), pod)
Expect(err).To(BeNil())
Expect(pod.Spec.HostNetwork).To(Equal(false))
+ Expect(pod.Spec.SecurityContext).To(BeNil())
+ Expect(pod.Spec.DNSConfig).To(BeNil())
+ Expect(pod.Spec.Containers[0].WorkingDir).To(Equal(""))
+ Expect(pod.Spec.Containers[0].Env).To(BeNil())
numContainers := 0
for range pod.Spec.Containers {
@@ -103,6 +107,7 @@ var _ = Describe("Podman generate kube", func() {
err = yaml.Unmarshal(kube.Out.Contents(), pod)
Expect(err).To(BeNil())
Expect(kube.OutputToString()).To(ContainSubstring("type: spc_t"))
+
})
It("podman generate service kube on container with --security-opt type", func() {
@@ -1079,7 +1084,7 @@ USER test1`
top1.WaitWithDefaultTimeout()
Expect(top1).Should(Exit(0))
- top2 := podmanTest.Podman([]string{"run", "-dt", "--name", "top2", "--pod", "pod1", "--label", "io.containers.autoupdate=registry", "--label", "io.containers.autoupdate.authfile=/some/authfile.json", ALPINE, "top"})
+ top2 := podmanTest.Podman([]string{"run", "-dt", "--name", "top2", "--workdir", "/root", "--pod", "pod1", "--label", "io.containers.autoupdate=registry", "--label", "io.containers.autoupdate.authfile=/some/authfile.json", ALPINE, "top"})
top2.WaitWithDefaultTimeout()
Expect(top2).Should(Exit(0))
@@ -1090,6 +1095,8 @@ USER test1`
pod := new(v1.Pod)
err := yaml.Unmarshal(kube.Out.Contents(), pod)
Expect(err).To(BeNil())
+ Expect(pod.Spec.Containers[0].WorkingDir).To(Equal(""))
+ Expect(pod.Spec.Containers[1].WorkingDir).To(Equal("/root"))
for _, ctr := range []string{"top1", "top2"} {
v, ok := pod.GetAnnotations()["io.containers.autoupdate/"+ctr]
diff --git a/test/e2e/libpod_suite_remote_test.go b/test/e2e/libpod_suite_remote_test.go
index 3115c246f..ad511cc9e 100644
--- a/test/e2e/libpod_suite_remote_test.go
+++ b/test/e2e/libpod_suite_remote_test.go
@@ -38,11 +38,25 @@ func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration
return &PodmanSessionIntegration{podmanSession}
}
+// PodmanSystemdScope runs the podman command in a new systemd scope
+func (p *PodmanTestIntegration) PodmanSystemdScope(args []string) *PodmanSessionIntegration {
+ var remoteArgs = []string{"--remote", "--url", p.RemoteSocket}
+ remoteArgs = append(remoteArgs, args...)
+
+ wrapper := []string{"systemd-run", "--scope"}
+ if rootless.IsRootless() {
+ wrapper = []string{"systemd-run", "--scope", "--user"}
+ }
+
+ podmanSession := p.PodmanAsUserBase(remoteArgs, 0, 0, "", nil, false, false, wrapper, nil)
+ return &PodmanSessionIntegration{podmanSession}
+}
+
// PodmanExtraFiles is the exec call to podman on the filesystem and passes down extra files
func (p *PodmanTestIntegration) PodmanExtraFiles(args []string, extraFiles []*os.File) *PodmanSessionIntegration {
var remoteArgs = []string{"--remote", "--url", p.RemoteSocket}
remoteArgs = append(remoteArgs, args...)
- podmanSession := p.PodmanAsUserBase(remoteArgs, 0, 0, "", nil, false, false, extraFiles)
+ podmanSession := p.PodmanAsUserBase(remoteArgs, 0, 0, "", nil, false, false, nil, extraFiles)
return &PodmanSessionIntegration{podmanSession}
}
diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go
index cc03ccc96..6d2d3fee8 100644
--- a/test/e2e/libpod_suite_test.go
+++ b/test/e2e/libpod_suite_test.go
@@ -8,6 +8,8 @@ import (
"os"
"path/filepath"
"strings"
+
+ "github.com/containers/podman/v3/pkg/rootless"
)
func IsRemote() bool {
@@ -23,9 +25,19 @@ func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration
return &PodmanSessionIntegration{podmanSession}
}
+// PodmanSystemdScope runs the podman command in a new systemd scope
+func (p *PodmanTestIntegration) PodmanSystemdScope(args []string) *PodmanSessionIntegration {
+ wrapper := []string{"systemd-run", "--scope"}
+ if rootless.IsRootless() {
+ wrapper = []string{"systemd-run", "--scope", "--user"}
+ }
+ podmanSession := p.PodmanAsUserBase(args, 0, 0, "", nil, false, false, wrapper, nil)
+ return &PodmanSessionIntegration{podmanSession}
+}
+
// PodmanExtraFiles is the exec call to podman on the filesystem and passes down extra files
func (p *PodmanTestIntegration) PodmanExtraFiles(args []string, extraFiles []*os.File) *PodmanSessionIntegration {
- podmanSession := p.PodmanAsUserBase(args, 0, 0, "", nil, false, false, extraFiles)
+ podmanSession := p.PodmanAsUserBase(args, 0, 0, "", nil, false, false, nil, extraFiles)
return &PodmanSessionIntegration{podmanSession}
}
diff --git a/test/e2e/logs_test.go b/test/e2e/logs_test.go
index 71d30f063..16e48da19 100644
--- a/test/e2e/logs_test.go
+++ b/test/e2e/logs_test.go
@@ -13,6 +13,19 @@ import (
. "github.com/onsi/gomega/gexec"
)
+func isEventBackendJournald(podmanTest *PodmanTestIntegration) bool {
+ if !podmanTest.RemoteTest {
+ // If not remote test, '--events-backend' is set to 'file' or 'none'
+ return false
+ }
+ info := podmanTest.Podman([]string{"info", "--format", "{{.Host.EventLogger}}"})
+ info.WaitWithDefaultTimeout()
+ if info.OutputToString() == "journald" {
+ return true
+ }
+ return false
+}
+
var _ = Describe("Podman logs", func() {
var (
tempdir string
@@ -38,8 +51,18 @@ var _ = Describe("Podman logs", func() {
})
for _, log := range []string{"k8s-file", "journald", "json-file"} {
+ // This is important to move the 'log' var to the correct scope under Ginkgo flow.
+ log := log
+
+ skipIfJournaldInContainer := func() {
+ if log == "journald" {
+ SkipIfInContainer("journalctl inside a container doesn't work correctly")
+ }
+ }
It("all lines: "+log, func() {
+ skipIfJournaldInContainer()
+
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
@@ -53,6 +76,8 @@ var _ = Describe("Podman logs", func() {
})
It("tail two lines: "+log, func() {
+ skipIfJournaldInContainer()
+
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
@@ -65,6 +90,8 @@ var _ = Describe("Podman logs", func() {
})
It("tail zero lines: "+log, func() {
+ skipIfJournaldInContainer()
+
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
@@ -77,6 +104,8 @@ var _ = Describe("Podman logs", func() {
})
It("tail 99 lines: "+log, func() {
+ skipIfJournaldInContainer()
+
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
@@ -89,6 +118,8 @@ var _ = Describe("Podman logs", func() {
})
It("tail 800 lines: "+log, func() {
+ skipIfJournaldInContainer()
+
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "i=1; while [ \"$i\" -ne 1000 ]; do echo \"line $i\"; i=$((i + 1)); done"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
@@ -101,6 +132,8 @@ var _ = Describe("Podman logs", func() {
})
It("tail 2 lines with timestamps: "+log, func() {
+ skipIfJournaldInContainer()
+
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
@@ -113,6 +146,8 @@ var _ = Describe("Podman logs", func() {
})
It("since time 2017-08-07: "+log, func() {
+ skipIfJournaldInContainer()
+
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
@@ -125,6 +160,8 @@ var _ = Describe("Podman logs", func() {
})
It("since duration 10m: "+log, func() {
+ skipIfJournaldInContainer()
+
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
@@ -137,6 +174,8 @@ var _ = Describe("Podman logs", func() {
})
It("until duration 10m: "+log, func() {
+ skipIfJournaldInContainer()
+
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
@@ -149,6 +188,7 @@ var _ = Describe("Podman logs", func() {
})
It("until time NOW: "+log, func() {
+ skipIfJournaldInContainer()
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
@@ -165,13 +205,17 @@ var _ = Describe("Podman logs", func() {
})
It("latest and container name should fail: "+log, func() {
+ skipIfJournaldInContainer()
+
results := podmanTest.Podman([]string{"logs", "-l", "foobar"})
results.WaitWithDefaultTimeout()
Expect(results).To(ExitWithError())
})
It("two containers showing short container IDs: "+log, func() {
+ skipIfJournaldInContainer()
SkipIfRemote("FIXME: podman-remote logs does not support showing two containers at the same time")
+
log1 := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
log1.WaitWithDefaultTimeout()
Expect(log1).Should(Exit(0))
@@ -192,6 +236,8 @@ var _ = Describe("Podman logs", func() {
})
It("podman logs on a created container should result in 0 exit code: "+log, func() {
+ skipIfJournaldInContainer()
+
session := podmanTest.Podman([]string{"create", "--log-driver", log, "-t", "--name", "log", ALPINE})
session.WaitWithDefaultTimeout()
Expect(session).To(Exit(0))
@@ -202,6 +248,8 @@ var _ = Describe("Podman logs", func() {
})
It("streaming output: "+log, func() {
+ skipIfJournaldInContainer()
+
containerName := "logs-f"
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName, "-dt", ALPINE, "sh", "-c", "echo podman-1; sleep 1; echo podman-2"})
@@ -210,6 +258,14 @@ var _ = Describe("Podman logs", func() {
results := podmanTest.Podman([]string{"logs", "-f", containerName})
results.WaitWithDefaultTimeout()
+
+ if log == "journald" && !isEventBackendJournald(podmanTest) {
+ // --follow + journald log-driver is only supported with journald events-backend(PR #10431)
+ Expect(results).To(Exit(125))
+ Expect(results.ErrorToString()).To(ContainSubstring("using --follow with the journald --log-driver but without the journald --events-backend"))
+ return
+ }
+
Expect(results).To(Exit(0))
Expect(results.OutputToString()).To(ContainSubstring("podman-1"))
@@ -233,6 +289,8 @@ var _ = Describe("Podman logs", func() {
})
It("follow output stopped container: "+log, func() {
+ skipIfJournaldInContainer()
+
containerName := "logs-f"
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName, "-d", ALPINE, "true"})
@@ -241,10 +299,17 @@ var _ = Describe("Podman logs", func() {
results := podmanTest.Podman([]string{"logs", "-f", containerName})
results.WaitWithDefaultTimeout()
+ if log == "journald" && !isEventBackendJournald(podmanTest) {
+ // --follow + journald log-driver is only supported with journald events-backend(PR #10431)
+ Expect(results).To(Exit(125))
+ return
+ }
Expect(results).To(Exit(0))
})
It("using container with container log-size: "+log, func() {
+ skipIfJournaldInContainer()
+
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--log-opt=max-size=10k", "-d", ALPINE, "sh", "-c", "echo podman podman podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
@@ -266,6 +331,8 @@ var _ = Describe("Podman logs", func() {
})
It("Make sure logs match expected length: "+log, func() {
+ skipIfJournaldInContainer()
+
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-t", "--name", "test", ALPINE, "sh", "-c", "echo 1; echo 2"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
@@ -284,6 +351,8 @@ var _ = Describe("Podman logs", func() {
})
It("podman logs test stdout and stderr: "+log, func() {
+ skipIfJournaldInContainer()
+
cname := "log-test"
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", cname, ALPINE, "sh", "-c", "echo stdout; echo stderr >&2"})
logc.WaitWithDefaultTimeout()
diff --git a/test/e2e/pod_rm_test.go b/test/e2e/pod_rm_test.go
index c5d91d679..ac1f322ef 100644
--- a/test/e2e/pod_rm_test.go
+++ b/test/e2e/pod_rm_test.go
@@ -301,4 +301,21 @@ var _ = Describe("Podman pod rm", func() {
Expect(session).Should(Exit(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
})
+
+ It("podman pod rm with exited containers", func() {
+ _, ec, podid := podmanTest.CreatePod(nil)
+ Expect(ec).To(Equal(0))
+
+ session := podmanTest.Podman([]string{"run", "--pod", podid, ALPINE})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"run", "--pod", podid, ALPINE})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ result := podmanTest.Podman([]string{"pod", "rm", podid})
+ result.WaitWithDefaultTimeout()
+ Expect(result).Should(Exit(0))
+ })
})
diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go
index 84707732b..8d3b19b88 100644
--- a/test/e2e/run_networking_test.go
+++ b/test/e2e/run_networking_test.go
@@ -357,6 +357,26 @@ var _ = Describe("Podman run networking", func() {
Expect(ncBusy).To(ExitWithError())
})
+ It("podman run slirp4netns verify net.ipv6.conf.default.accept_dad=0", func() {
+ session := podmanTest.Podman([]string{"run", "--network", "slirp4netns:enable_ipv6=true", ALPINE, "ip", "addr"})
+ session.Wait(30)
+ Expect(session).Should(Exit(0))
+ // check the ipv6 setup id done without delay (https://github.com/containers/podman/issues/11062)
+ Expect(session.OutputToString()).To(ContainSubstring("inet6 fd00::"))
+
+ const ipv6ConfDefaultAcceptDadSysctl = "/proc/sys/net/ipv6/conf/all/accept_dad"
+
+ cat := SystemExec("cat", []string{ipv6ConfDefaultAcceptDadSysctl})
+ cat.Wait(30)
+ Expect(cat).Should(Exit(0))
+ sysctlValue := cat.OutputToString()
+
+ session = podmanTest.Podman([]string{"run", "--network", "slirp4netns:enable_ipv6=true", ALPINE, "cat", ipv6ConfDefaultAcceptDadSysctl})
+ session.Wait(30)
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(Equal(sysctlValue))
+ })
+
It("podman run network expose host port 18082 to container port 8000 using slirp4netns port handler", func() {
session := podmanTest.Podman([]string{"run", "--network", "slirp4netns:port_handler=slirp4netns", "-dt", "-p", "18082:8000", ALPINE, "/bin/sh"})
session.Wait(30)
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index b6743f4b7..ca39989cd 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -1322,13 +1322,13 @@ USER mail`, BB)
}
}
- container := podmanTest.Podman([]string{"run", "--rm", "--cgroups=split", ALPINE, "cat", "/proc/self/cgroup"})
+ container := podmanTest.PodmanSystemdScope([]string{"run", "--rm", "--cgroups=split", ALPINE, "cat", "/proc/self/cgroup"})
container.WaitWithDefaultTimeout()
Expect(container).Should(Exit(0))
checkLines(container.OutputToStringArray())
// check that --cgroups=split is honored also when a container runs in a pod
- container = podmanTest.Podman([]string{"run", "--rm", "--pod", "new:split-test-pod", "--cgroups=split", ALPINE, "cat", "/proc/self/cgroup"})
+ container = podmanTest.PodmanSystemdScope([]string{"run", "--rm", "--pod", "new:split-test-pod", "--cgroups=split", ALPINE, "cat", "/proc/self/cgroup"})
container.WaitWithDefaultTimeout()
Expect(container).Should(Exit(0))
checkLines(container.OutputToStringArray())
diff --git a/test/e2e/system_reset_test.go b/test/e2e/system_reset_test.go
index 102526a46..93ab166cd 100644
--- a/test/e2e/system_reset_test.go
+++ b/test/e2e/system_reset_test.go
@@ -60,6 +60,8 @@ var _ = Describe("podman system reset", func() {
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
+ Expect(session.ErrorToString()).To(Not(ContainSubstring("Failed to add pause process")))
+
// If remote then the API service should have exited
// On local tests this is a noop
podmanTest.StartRemoteService()
diff --git a/test/e2e/systemd_test.go b/test/e2e/systemd_test.go
index a1b25b723..98def3d8f 100644
--- a/test/e2e/systemd_test.go
+++ b/test/e2e/systemd_test.go
@@ -4,7 +4,6 @@ import (
"io/ioutil"
"os"
"strings"
- "time"
. "github.com/containers/podman/v3/test/utils"
. "github.com/onsi/ginkgo"
@@ -82,27 +81,13 @@ WantedBy=multi-user.target
run := podmanTest.Podman([]string{"run", "--name", ctrName, "-t", "-i", "-d", ubi_init, "/sbin/init"})
run.WaitWithDefaultTimeout()
Expect(run).Should(Exit(0))
- ctrID := run.OutputToString()
logs := podmanTest.Podman([]string{"logs", ctrName})
logs.WaitWithDefaultTimeout()
Expect(logs).Should(Exit(0))
// Give container 10 seconds to start
- started := false
- for i := 0; i < 10; i++ {
- runningCtrs := podmanTest.Podman([]string{"ps", "-q", "--no-trunc"})
- runningCtrs.WaitWithDefaultTimeout()
- Expect(runningCtrs).Should(Exit(0))
-
- if strings.Contains(runningCtrs.OutputToString(), ctrID) {
- started = true
- break
- }
-
- time.Sleep(1 * time.Second)
- }
-
+ started := podmanTest.WaitContainerReady(ctrName, "Reached target Multi-User System.", 30, 1)
Expect(started).To(BeTrue())
systemctl := podmanTest.Podman([]string{"exec", "-t", "-i", ctrName, "systemctl", "status", "--no-pager"})
diff --git a/test/e2e/trust_test.go b/test/e2e/trust_test.go
index 7f97f280a..b591e1c02 100644
--- a/test/e2e/trust_test.go
+++ b/test/e2e/trust_test.go
@@ -14,7 +14,8 @@ import (
var _ = Describe("Podman trust", func() {
var (
- tempdir string
+ tempdir string
+
err error
podmanTest *PodmanTestIntegration
)
@@ -38,21 +39,17 @@ var _ = Describe("Podman trust", func() {
})
It("podman image trust show", func() {
- path, err := os.Getwd()
- if err != nil {
- os.Exit(1)
- }
- session := podmanTest.Podman([]string{"image", "trust", "show", "--registrypath", filepath.Dir(path), "--policypath", filepath.Join(filepath.Dir(path), "policy.json")})
+ session := podmanTest.Podman([]string{"image", "trust", "show", "--registrypath", filepath.Join(INTEGRATION_ROOT, "test"), "--policypath", filepath.Join(INTEGRATION_ROOT, "test/policy.json")})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
outArray := session.OutputToStringArray()
Expect(len(outArray)).To(Equal(3))
- // image order is not guaranteed. All we can do is check that
- // these strings appear in output, we can't cross-check them.
- Expect(session.OutputToString()).To(ContainSubstring("accept"))
- Expect(session.OutputToString()).To(ContainSubstring("reject"))
- Expect(session.OutputToString()).To(ContainSubstring("signed"))
+ // Repository order is not guaranteed. So, check that
+ // all expected lines appear in output; we also check total number of lines, so that handles all of them.
+ Expect(string(session.Out.Contents())).To(MatchRegexp(`(?m)^default\s+accept\s*$`))
+ Expect(string(session.Out.Contents())).To(MatchRegexp(`(?m)^docker.io/library/hello-world\s+reject\s*$`))
+ Expect(string(session.Out.Contents())).To(MatchRegexp(`(?m)^registry.access.redhat.com\s+signedBy\s+security@redhat.com, security@redhat.com\s+https://access.redhat.com/webassets/docker/content/sigstore\s*$`))
})
It("podman image trust set", func() {
@@ -76,24 +73,52 @@ var _ = Describe("Podman trust", func() {
})
It("podman image trust show --json", func() {
- session := podmanTest.Podman([]string{"image", "trust", "show", "--json"})
+ session := podmanTest.Podman([]string{"image", "trust", "show", "--registrypath", filepath.Join(INTEGRATION_ROOT, "test"), "--policypath", filepath.Join(INTEGRATION_ROOT, "test/policy.json"), "--json"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.IsJSONOutputValid()).To(BeTrue())
var teststruct []map[string]string
json.Unmarshal(session.Out.Contents(), &teststruct)
- Expect(teststruct[0]["name"]).To(Equal("* (default)"))
- Expect(teststruct[0]["repo_name"]).To(Equal("default"))
- Expect(teststruct[0]["type"]).To(Equal("accept"))
- Expect(teststruct[1]["type"]).To(Equal("insecureAcceptAnything"))
+ Expect(len(teststruct)).To(Equal(3))
+ // To ease comparison, group the unordered array of repos by repo (and we expect only one entry by repo, so order within groups doesn’t matter)
+ repoMap := map[string][]map[string]string{}
+ for _, e := range teststruct {
+ key := e["name"]
+ repoMap[key] = append(repoMap[key], e)
+ }
+ Expect(repoMap).To(Equal(map[string][]map[string]string{
+ "* (default)": {{
+ "name": "* (default)",
+ "repo_name": "default",
+ "sigstore": "",
+ "transport": "",
+ "type": "accept",
+ }},
+ "docker.io/library/hello-world": {{
+ "name": "docker.io/library/hello-world",
+ "repo_name": "docker.io/library/hello-world",
+ "sigstore": "",
+ "transport": "",
+ "type": "reject",
+ }},
+ "registry.access.redhat.com": {{
+ "name": "registry.access.redhat.com",
+ "repo_name": "registry.access.redhat.com",
+ "sigstore": "https://access.redhat.com/webassets/docker/content/sigstore",
+ "transport": "",
+ "type": "signedBy",
+ "gpg_id": "security@redhat.com, security@redhat.com",
+ }},
+ }))
})
It("podman image trust show --raw", func() {
- session := podmanTest.Podman([]string{"image", "trust", "show", "--raw"})
+ session := podmanTest.Podman([]string{"image", "trust", "show", "--policypath", filepath.Join(INTEGRATION_ROOT, "test/policy.json"), "--raw"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
+ contents, err := ioutil.ReadFile(filepath.Join(INTEGRATION_ROOT, "test/policy.json"))
+ Expect(err).ShouldNot(HaveOccurred())
Expect(session.IsJSONOutputValid()).To(BeTrue())
- Expect(session.OutputToString()).To(ContainSubstring("default"))
- Expect(session.OutputToString()).To(ContainSubstring("insecureAcceptAnything"))
+ Expect(string(session.Out.Contents())).To(Equal(string(contents) + "\n"))
})
})
diff --git a/test/e2e/version_test.go b/test/e2e/version_test.go
index 75986e671..9398248b8 100644
--- a/test/e2e/version_test.go
+++ b/test/e2e/version_test.go
@@ -31,7 +31,6 @@ var _ = Describe("Podman version", func() {
f := CurrentGinkgoTestDescription()
processTestResult(f)
podmanTest.SeedImages()
-
})
It("podman version", func() {
@@ -96,4 +95,13 @@ var _ = Describe("Podman version", func() {
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
})
+
+ It("podman help", func() {
+ session := podmanTest.Podman([]string{"help"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.Out.Contents()).Should(
+ ContainSubstring("Display the Podman version information"),
+ )
+ })
})
diff --git a/test/system/015-help.bats b/test/system/015-help.bats
index 5f38c34a1..b0795b524 100644
--- a/test/system/015-help.bats
+++ b/test/system/015-help.bats
@@ -86,6 +86,12 @@ function check_help() {
run_podman 125 "$@" $cmd -l nonexistent-container
is "$output" "Error: .*--latest and \(containers\|pods\|arguments\) cannot be used together" \
"'$command_string' with both -l and container"
+
+ # Combine -l and -a, too (but spell it as --all, because "-a"
+ # means "attach" in podman container start)
+ run_podman 125 "$@" $cmd --all --latest
+ is "$output" "Error: \(--all and --latest cannot be used together\|--all, --latest and containers cannot be used together\|--all, --latest and arguments cannot be used together\|unknown flag\)" \
+ "'$command_string' with both --all and --latest"
fi
fi
diff --git a/test/system/030-run.bats b/test/system/030-run.bats
index 8640d427a..2900540de 100644
--- a/test/system/030-run.bats
+++ b/test/system/030-run.bats
@@ -67,6 +67,11 @@ echo $rand | 0 | $rand
is "$output" ".*invalidflag" "failed when passing undefined flags to the runtime"
}
+@test "podman run --memory=0 runtime option" {
+ run_podman run --memory=0 --rm $IMAGE echo hello
+ is "$output" "hello" "failed to run when --memory is set to 0"
+}
+
# 'run --preserve-fds' passes a number of additional file descriptors into the container
@test "podman run --preserve-fds" {
skip_if_remote "preserve-fds is meaningless over remote"
diff --git a/test/system/045-start.bats b/test/system/045-start.bats
index 7e4bbde8d..2ea057cd3 100644
--- a/test/system/045-start.bats
+++ b/test/system/045-start.bats
@@ -36,10 +36,6 @@ load helpers
expected="Error: either start all containers or the container(s) provided in the arguments"
run_podman 125 start --all 12333
is "$output" "$expected" "start --all, with args, throws error"
- if ! is_remote; then
- run_podman 125 start --all --latest
- is "$output" "$expected" "podman start --all --latest"
- fi
}
@test "podman start --filter - start only containers that match the filter" {
diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats
index fc1a7c9f0..3263f3c82 100644
--- a/test/system/500-networking.bats
+++ b/test/system/500-networking.bats
@@ -167,6 +167,13 @@ load helpers
$IMAGE nc -l -n -v -p $myport
cid="$output"
+ # FIXME: debugging for #11871
+ run_podman exec $cid cat /etc/resolv.conf
+ if is_rootless; then
+ run_podman unshare --rootless-cni cat /etc/resolv.conf
+ fi
+ ps uxww
+
# check that dns is working inside the container
run_podman exec $cid nslookup google.com
diff --git a/test/upgrade/test-upgrade.bats b/test/upgrade/test-upgrade.bats
index 5cb302a85..c9c44839f 100644
--- a/test/upgrade/test-upgrade.bats
+++ b/test/upgrade/test-upgrade.bats
@@ -121,8 +121,15 @@ EOF
# Clean up vestiges of previous run
$PODMAN rm -f podman_parent || true
- # Not entirely a NOP! This is just so we get /run/crun created on a CI VM
- $PODMAN run --rm $OLD_PODMAN true
+
+ local netname=testnet-$(random_string 10)
+ $PODMAN network create $netname
+
+ # Not entirely a NOP! This is just so we get the /run/... mount points created on a CI VM
+ # --mac-address is needed to create /run/cni, --network is needed to create /run/containers for dnsname
+ $PODMAN run --rm --mac-address 78:28:a6:8d:24:8a --network $netname $OLD_PODMAN true
+ $PODMAN network rm -f $netname
+
#
# Use new-podman to run the above script under old-podman.
@@ -134,7 +141,8 @@ EOF
#
# mount /etc/containers/storage.conf to use the same storage settings as on the host
# mount /dev/shm because the container locks are stored there
- # mount /var/lib/cni and /etc/cni/net.d for cni networking
+ # mount /var/lib/cni, /run/cni and /etc/cni/net.d for cni networking
+ # mount /run/containers for the dnsname plugin
#
$PODMAN run -d --name podman_parent --pid=host \
--privileged \
@@ -145,6 +153,8 @@ EOF
-v /dev/fuse:/dev/fuse \
-v /run/crun:/run/crun \
-v /run/netns:/run/netns:rshared \
+ -v /run/containers:/run/containers \
+ -v /run/cni:/run/cni \
-v /var/lib/cni:/var/lib/cni \
-v /etc/cni/net.d:/etc/cni/net.d \
-v /dev/shm:/dev/shm \
diff --git a/test/utils/podmantest_test.go b/test/utils/podmantest_test.go
index 9bd1c4a66..1bb9ecb6b 100644
--- a/test/utils/podmantest_test.go
+++ b/test/utils/podmantest_test.go
@@ -23,7 +23,7 @@ var _ = Describe("PodmanTest test", func() {
FakeOutputs["check"] = []string{"check"}
os.Setenv("HOOK_OPTION", "hook_option")
env := os.Environ()
- session := podmanTest.PodmanAsUserBase([]string{"check"}, 1000, 1000, "", env, true, false, nil)
+ session := podmanTest.PodmanAsUserBase([]string{"check"}, 1000, 1000, "", env, true, false, nil, nil)
os.Unsetenv("HOOK_OPTION")
session.WaitWithDefaultTimeout()
Expect(session.Command.Process).ShouldNot(BeNil())
diff --git a/test/utils/utils.go b/test/utils/utils.go
index bfefc58ec..d4d5e6e2f 100644
--- a/test/utils/utils.go
+++ b/test/utils/utils.go
@@ -66,27 +66,31 @@ func (p *PodmanTest) MakeOptions(args []string, noEvents, noCache bool) []string
// PodmanAsUserBase exec podman as user. uid and gid is set for credentials usage. env is used
// to record the env for debugging
-func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string, env []string, noEvents, noCache bool, extraFiles []*os.File) *PodmanSession {
+func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string, env []string, noEvents, noCache bool, wrapper []string, extraFiles []*os.File) *PodmanSession {
var command *exec.Cmd
podmanOptions := p.MakeOptions(args, noEvents, noCache)
podmanBinary := p.PodmanBinary
if p.RemoteTest {
podmanBinary = p.RemotePodmanBinary
}
+
+ runCmd := append(wrapper, podmanBinary)
if p.RemoteTest {
podmanOptions = append([]string{"--remote", "--url", p.RemoteSocket}, podmanOptions...)
}
if env == nil {
- fmt.Printf("Running: %s %s\n", podmanBinary, strings.Join(podmanOptions, " "))
+ fmt.Printf("Running: %s %s\n", strings.Join(runCmd, " "), strings.Join(podmanOptions, " "))
} else {
- fmt.Printf("Running: (env: %v) %s %s\n", env, podmanBinary, strings.Join(podmanOptions, " "))
+ fmt.Printf("Running: (env: %v) %s %s\n", env, strings.Join(runCmd, " "), strings.Join(podmanOptions, " "))
}
if uid != 0 || gid != 0 {
pythonCmd := fmt.Sprintf("import os; import sys; uid = %d; gid = %d; cwd = '%s'; os.setgid(gid); os.setuid(uid); os.chdir(cwd) if len(cwd)>0 else True; os.execv(sys.argv[1], sys.argv[1:])", gid, uid, cwd)
- nsEnterOpts := append([]string{"-c", pythonCmd, podmanBinary}, podmanOptions...)
+ runCmd = append(runCmd, podmanOptions...)
+ nsEnterOpts := append([]string{"-c", pythonCmd}, runCmd...)
command = exec.Command("python", nsEnterOpts...)
} else {
- command = exec.Command(podmanBinary, podmanOptions...)
+ runCmd = append(runCmd, podmanOptions...)
+ command = exec.Command(runCmd[0], runCmd[1:]...)
}
if env != nil {
command.Env = env
@@ -106,7 +110,7 @@ func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string
// PodmanBase exec podman with default env.
func (p *PodmanTest) PodmanBase(args []string, noEvents, noCache bool) *PodmanSession {
- return p.PodmanAsUserBase(args, 0, 0, "", nil, noEvents, noCache, nil)
+ return p.PodmanAsUserBase(args, 0, 0, "", nil, noEvents, noCache, nil, nil)
}
// WaitForContainer waits on a started container
diff --git a/troubleshooting.md b/troubleshooting.md
index a6c014625..4bc115e44 100644
--- a/troubleshooting.md
+++ b/troubleshooting.md
@@ -51,9 +51,9 @@ In cases where the container image runs as a specific, non-root user, though, th
solution is to fix the user namespace. This would include container images such as
the Jupyter Notebook image (which runs as "jovyan") and the Postgres image (which runs
as "postgres"). In either case, use the `--userns` switch to map user namespaces,
-most of the time by using keep_id option.
+most of the time by using the **keep-id** option.
-$ podman run -v "$PWD":/home/jovyan/work --userns=keep_id jupyter/scipy-notebook
+$ podman run -v "$PWD":/home/jovyan/work --userns=keep-id jupyter/scipy-notebook
---
### 3) No such image or Bare keys cannot contain ':'
diff --git a/utils/utils.go b/utils/utils.go
index b08630d2f..109ae088b 100644
--- a/utils/utils.go
+++ b/utils/utils.go
@@ -14,6 +14,7 @@ import (
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/cgroups"
"github.com/containers/storage/pkg/archive"
+ "github.com/godbus/dbus/v5"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -177,13 +178,26 @@ func RunsOnSystemd() bool {
func moveProcessToScope(pidPath, slice, scope string) error {
data, err := ioutil.ReadFile(pidPath)
if err != nil {
+ // do not raise an error if the file doesn't exist
+ if os.IsNotExist(err) {
+ return nil
+ }
return errors.Wrapf(err, "cannot read pid file %s", pidPath)
}
pid, err := strconv.ParseUint(string(data), 10, 0)
if err != nil {
return errors.Wrapf(err, "cannot parse pid file %s", pidPath)
}
- return RunUnderSystemdScope(int(pid), slice, scope)
+ err = RunUnderSystemdScope(int(pid), slice, scope)
+
+ // If the PID is not valid anymore, do not return an error.
+ if dbusErr, ok := err.(dbus.Error); ok {
+ if dbusErr.Name == "org.freedesktop.DBus.Error.UnixProcessIdUnknown" {
+ return nil
+ }
+ }
+
+ return err
}
// MovePauseProcessToScope moves the pause process used for rootless mode to keep the namespaces alive to
@@ -191,8 +205,8 @@ func moveProcessToScope(pidPath, slice, scope string) error {
func MovePauseProcessToScope(pausePidPath string) {
err := moveProcessToScope(pausePidPath, "user.slice", "podman-pause.scope")
if err != nil {
- unified, err := cgroups.IsCgroup2UnifiedMode()
- if err != nil {
+ unified, err2 := cgroups.IsCgroup2UnifiedMode()
+ if err2 != nil {
logrus.Warnf("Failed to detect if running with cgroup unified: %v", err)
}
if RunsOnSystemd() && unified {
diff --git a/vendor/github.com/godbus/dbus/v5/auth.go b/vendor/github.com/godbus/dbus/v5/auth.go
index eb0b2f434..a59b4c0eb 100644
--- a/vendor/github.com/godbus/dbus/v5/auth.go
+++ b/vendor/github.com/godbus/dbus/v5/auth.go
@@ -53,7 +53,7 @@ type Auth interface {
// bus. Auth must not be called on shared connections.
func (conn *Conn) Auth(methods []Auth) error {
if methods == nil {
- uid := strconv.Itoa(os.Getuid())
+ uid := strconv.Itoa(os.Geteuid())
methods = []Auth{AuthExternal(uid), AuthCookieSha1(uid, getHomeDir())}
}
in := bufio.NewReader(conn.transport)
diff --git a/vendor/github.com/godbus/dbus/v5/conn.go b/vendor/github.com/godbus/dbus/v5/conn.go
index cb8966a74..76fc5cde3 100644
--- a/vendor/github.com/godbus/dbus/v5/conn.go
+++ b/vendor/github.com/godbus/dbus/v5/conn.go
@@ -73,7 +73,7 @@ func SessionBus() (conn *Conn, err error) {
return
}
-func getSessionBusAddress() (string, error) {
+func getSessionBusAddress(autolaunch bool) (string, error) {
if address := os.Getenv("DBUS_SESSION_BUS_ADDRESS"); address != "" && address != "autolaunch:" {
return address, nil
@@ -81,12 +81,26 @@ func getSessionBusAddress() (string, error) {
os.Setenv("DBUS_SESSION_BUS_ADDRESS", address)
return address, nil
}
+ if !autolaunch {
+ return "", errors.New("dbus: couldn't determine address of session bus")
+ }
return getSessionBusPlatformAddress()
}
// SessionBusPrivate returns a new private connection to the session bus.
func SessionBusPrivate(opts ...ConnOption) (*Conn, error) {
- address, err := getSessionBusAddress()
+ address, err := getSessionBusAddress(true)
+ if err != nil {
+ return nil, err
+ }
+
+ return Dial(address, opts...)
+}
+
+// SessionBusPrivate returns a new private connection to the session bus. If
+// the session bus is not already open, do not attempt to launch it.
+func SessionBusPrivateNoAutoStartup(opts ...ConnOption) (*Conn, error) {
+ address, err := getSessionBusAddress(false)
if err != nil {
return nil, err
}
@@ -121,7 +135,7 @@ func SystemBus() (conn *Conn, err error) {
// ConnectSessionBus connects to the session bus.
func ConnectSessionBus(opts ...ConnOption) (*Conn, error) {
- address, err := getSessionBusAddress()
+ address, err := getSessionBusAddress(true)
if err != nil {
return nil, err
}
@@ -180,7 +194,7 @@ func Dial(address string, opts ...ConnOption) (*Conn, error) {
//
// Deprecated: use Dial with options instead.
func DialHandler(address string, handler Handler, signalHandler SignalHandler) (*Conn, error) {
- return Dial(address, WithSignalHandler(signalHandler))
+ return Dial(address, WithHandler(handler), WithSignalHandler(signalHandler))
}
// ConnOption is a connection option.
diff --git a/vendor/github.com/godbus/dbus/v5/message.go b/vendor/github.com/godbus/dbus/v5/message.go
index dd86aff4f..16693eb30 100644
--- a/vendor/github.com/godbus/dbus/v5/message.go
+++ b/vendor/github.com/godbus/dbus/v5/message.go
@@ -279,8 +279,8 @@ func (msg *Message) EncodeToWithFDs(out io.Writer, order binary.ByteOrder) (fds
// be either binary.LittleEndian or binary.BigEndian. If the message is not
// valid or an error occurs when writing, an error is returned.
func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) (err error) {
- _, err = msg.EncodeToWithFDs(out, order);
- return err;
+ _, err = msg.EncodeToWithFDs(out, order)
+ return err
}
// IsValid checks whether msg is a valid message and returns an
diff --git a/vendor/github.com/godbus/dbus/v5/transport_unixcred_netbsd.go b/vendor/github.com/godbus/dbus/v5/transport_unixcred_netbsd.go
new file mode 100644
index 000000000..af7bafdf9
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/v5/transport_unixcred_netbsd.go
@@ -0,0 +1,14 @@
+package dbus
+
+import "io"
+
+func (t *unixTransport) SendNullByte() error {
+ n, _, err := t.UnixConn.WriteMsgUnix([]byte{0}, nil, nil)
+ if err != nil {
+ return err
+ }
+ if n != 1 {
+ return io.ErrShortWrite
+ }
+ return nil
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 04bee22c9..fad1d5093 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -353,7 +353,7 @@ github.com/ghodss/yaml
github.com/go-logr/logr
# github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0
github.com/go-task/slim-sprig
-# github.com/godbus/dbus/v5 v5.0.5
+# github.com/godbus/dbus/v5 v5.0.6
github.com/godbus/dbus/v5
# github.com/gogo/protobuf v1.3.2
github.com/gogo/protobuf/gogoproto
diff --git a/version/version.go b/version/version.go
index e5d1f3d1c..9dd8b9a83 100644
--- a/version/version.go
+++ b/version/version.go
@@ -27,7 +27,7 @@ const (
// NOTE: remember to bump the version at the top
// of the top-level README.md file when this is
// bumped.
-var Version = semver.MustParse("3.4.2-dev")
+var Version = semver.MustParse("3.4.3-dev")
// See https://docs.docker.com/engine/api/v1.40/
// libpod compat handlers are expected to honor docker API versions